package com.nq.service.impl;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.nq.activaity.entity.StIntegralTask;
import com.nq.common.ServerResponse;
import com.nq.common.StockBuyTypeEnum;
import com.nq.common.SystemVersionEnum;
import com.nq.common.entity.StStockTickerDetails;
import com.nq.common.entity.StStockTickerKLineList;
import com.nq.common.entity.info.StockTickerListInfo;
import com.nq.dao.*;
import com.nq.dao.activaity.StIntegralTaskMapper;
import com.nq.dao.stock.StStockMapper;
import com.nq.dao.stock.UserStockSubscribePaymentMapper;
import com.nq.pojo.*;
import com.nq.pojo.vo.FundPositionRecordVo;
import com.nq.pojo.vo.StFundDetailsVo;
import com.nq.pojo.vo.StPositionDetailsVo;
import com.nq.service.*;
import com.nq.stock.entity.KLineDetail;
import com.nq.stock.entity.StIpo;
import com.nq.stock.entity.StStock;
import com.nq.stock.entity.UserStockSubscribePayment;
import com.nq.stock.service.IStIpoService;
import com.nq.utils.*;
import com.nq.utils.email.SendHTMLMail;
import com.nq.utils.redis.RedisShardedPoolUtils;
import com.nq.utils.stock.BuyAndSellUtils;
import com.nq.utils.stock.GeneratePosition;
import com.nq.utils.stock.GetStayDays;
import com.nq.utils.stock.pinyin.GetPyByChinese;
import com.nq.utils.stock.sina.SinaStockApi;
import com.nq.utils.task.tsanghi.StocksComponent;
import com.nq.vo.agent.AgentIncomeVO;
import com.nq.vo.page.StockPageInfo;
import com.nq.vo.position.*;
import com.nq.vo.stock.StockListVO;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

@Service("iUserPositionService")
public class UserPositionServiceImpl implements IUserPositionService {

    private static final Logger log = LoggerFactory.getLogger(UserPositionServiceImpl.class);

    @Resource
    private UserStockSubscribePaymentMapper userStockSubscribePaymentMapper;
    @Autowired
    UserPositionMapper userPositionMapper;

    @Autowired
    IUserService iUserService;

    @Autowired
    ISiteSettingService iSiteSettingService;

    @Autowired
    ISiteSpreadService iSiteSpreadService;

    @Autowired
    IStockService iStockService;

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserCashDetailMapper userCashDetailMapper;
    @Autowired
    IAgentUserService iAgentUserService;
    @Autowired
    AgentUserMapper agentUserMapper;
    @Autowired
    SiteTaskLogMapper siteTaskLogMapper;
    @Autowired
    StockMapper stockMapper;
    @Autowired
    AgentAgencyFeeMapper agentAgencyFeeMapper;
    @Autowired
    IAgentAgencyFeeService iAgentAgencyFeeService;
    @Autowired
    ISiteProductService iSiteProductService;

    @Autowired
    private UserPendingorderMapper userPendingorderMapper;
    @Autowired
    FundsApplyMapper fundsApplyMapper;
    @Autowired
    UserStockSubscribeMapper userStockSubscribeMapper;
    @Autowired
    StockSubscribeMapper stockSubscribeMapper;
    @Autowired
    UserIndexPositionMapper userIndexPositionMapper;
    @Autowired
    StockDzMapper stockDzMapper;
    @Autowired
    IStockFuturesService iStockFuturesService;
    @Autowired
    IStockCoinService iStockCoinService;
    @Autowired
    CurrencyUtils currencyUtils;

    @Resource
    private StStockMapper stStockMapper;
    @Resource
    private StFundApplyMapper stFundApplyMapper;
    @Resource
    private StFundApplyDetailMapper stFundApplyDetailMapper;
    @Resource
    private StocksComponent stocksComponent;
    @Resource
    private UserRechargeMapper userRechargeMapper;

    @Resource
    private UserPositionDetailMapper userPositionDetailMapper;

    @Resource
    private LogEditTransactionRecordsMapper logEditTransactionRecordsMapper;

    @Resource
    private IStLimitUpStockService stLimitUpStockService;
    @Resource
    private StIntegralTaskMapper integralTaskMapper;

    @Resource
    private StockDzService stockDzService;

    @Resource
    private IStIpoService stIpoService;

    @Autowired
    private SendHTMLMail sendHTMLMail;
    @Value("${spring.profiles.active}")
    private String active;



    @Resource
    private IStPremarketStockService stPremarketStockService;

    @Resource
    private StHolidaysMapper stHolidaysMapper;

    /**
     * 判断购买涨停板
     * @param stockCode
     * @param market
     * @param paramHttpServletRequest
     * @return
     */
    @Override
    public ServerResponse isBuyUp(String stockCode, String market, HttpServletRequest paramHttpServletRequest) {
        // 查询该股票的实时价格
        StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(market, stockCode);
        if (null == tickerDetails) {
            return ServerResponse.createByErrorMsg("查询股票实时价格失败！【tickerDetails】");
        }

        StockTickerListInfo tickerInfo = tickerDetails.getData();
        if (null == tickerInfo) {
            return ServerResponse.createByErrorMsg("查询股票实时价格失败！【tickerInfo】");
        }
        // 是否需要输入密码
        Map<String, Object> map = new HashMap<>();
        map.put("isNeedPwd", "0");
        // 不用管其他。以我这句话为准： B1=0 表示跌停 不可以卖出 S1=0 表示涨停，不可以买入
        // String s1 = tickerInfo.getS1();
        if (active.equals("india")) {
            // 获取股票涨停板设置
            StLimitUpStock stLimitUpStock = stLimitUpStockService.getLimitUpByCodeAndMarket(market, stockCode);
            // 如果等于null，说明没有特殊渠道
            if (null == stLimitUpStock) {
                return ServerResponse.createByErrorMsg("下单失败，无法购买涨停板股票。");
            }
            // 校验当前日期是否在有效期内
            Date startTime = stLimitUpStock.getStartTime();
            Date endTime = stLimitUpStock.getEndTime();
            // 当前日期
            Date currentTime = new Date();
            if (!currentTime.after(startTime) || !currentTime.before(endTime)) {
                return ServerResponse.createByErrorMsg("下单失败，该股票不在当前有效期内。");
            }
            map.put("isNeedPwd", "1");
            Integer stockNum = stLimitUpStock.getStockNum();
            map.put("stockNum", stockNum);
            return ServerResponse.createBySuccess(map);
        }
        return ServerResponse.createBySuccess(map);
    }

    /**
     * 市场股票购买
     * @param stockCode
     * @param market
     * @param buyNum
     * @param buyType
     * @param lever
     * @param profitTarget
     * @param stopTarget
     * @param request
     * @return
     * @throws Exception
     */
    @Transactional
    public ServerResponse buy(String stockCode,
                              String market,
                              Integer buyNum,
                              Integer buyType,
                              Integer lever,
                              BigDecimal profitTarget,
                              BigDecimal stopTarget,
                              HttpServletRequest request,
                              String payPwd) throws Exception {

        User user = this.iUserService.getCurrentRefreshUser(request);
        if (user == null) {
            return ServerResponse.createByErrorMsg("用户信息有误，请重新登录后尝试.");
        }

        // -------------- 幂等性调用（开始） --------------
        Integer userId = user.getId();

        String redisKey = "BUY_STOCK_" + userId + "_" + stockCode;

        String code = RedisShardedPoolUtils.get("BUY_STOCK_" + userId + "_" + stockCode);
        if (StringUtils.isNotBlank(code)) {
            return ServerResponse.createByErrorMsg("购买失败，请勿重新提交.");
        }
        RedisShardedPoolUtils.setEx(redisKey, stockCode, 1);

        // -------------- 幂等性调用（开始） --------------
//        if (!IdempotentUtils.judge(String.valueOf(user.getId()), this.getClass())) {
//            return ServerResponse.createByErrorMsg("Failed to buy, do not resubmit.");
//        }

        return actualPurchase(user, stockCode, market, buyNum, buyType, lever, profitTarget, stopTarget, StockBuyTypeEnum.BUY.getType(), payPwd);
    }

    /**
     * 涨停板股票购买
     * @param stockCode
     * @param market
     * @param buyNum
     * @param buyType
     * @param lever
     * @param profitTarget
     * @param stopTarget
     * @param request
     * @return
     * @throws Exception
     */
    @Transactional
    public ServerResponse upBuy(String stockCode,
                                String market,
                                Integer buyNum,
                                Integer buyType,
                                Integer lever,
                                BigDecimal profitTarget,
                                BigDecimal stopTarget,
                                String password,
                                HttpServletRequest request,
                                String payPwd) {
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (user == null) {
            return ServerResponse.createByErrorMsg("交易失败，用户不存在");
        }
        // -------------- 幂等性调用（开始） --------------


        Integer userId = user.getId();

        String redisKey = "BUY_STOCK_" + userId + "_" + stockCode;

        String code = RedisShardedPoolUtils.get("BUY_STOCK_" + userId + "_" + stockCode);
        if (StringUtils.isNotBlank(code)) {
            return ServerResponse.createByErrorMsg("操作失败，请勿重复提交");
        }
        RedisShardedPoolUtils.setEx(redisKey, stockCode, 1);



//        if (!IdempotentUtils.judge(String.valueOf(user.getId()), this.getClass())) {
//            return ServerResponse.createByErrorMsg("Failed to sell, do not resubmit.");
//        }
        // 获取涨停板设置
        StLimitUpStock stLimitUpStock = stLimitUpStockService.getLimitUpByCodeAndMarket(market, stockCode);
        // 如果不等于null，说明需要校验密码
        if (null == stLimitUpStock) {
            return ServerResponse.createByErrorMsg("交易失败，无法购买涨停板股票");
        }
        // 校验最小购买数量
        Integer stockNum = stLimitUpStock.getStockNum();
        if (buyNum < stockNum) {
            return ServerResponse.createByErrorMsg("购买数量不足最低要求：" + stockNum);
        }
        // 校验密码
        if (!SymmetricCryptoUtil.encryptPassword(password).equals(stLimitUpStock.getPassword())) {
            boolean isLocked = iUserService.isLocked(User.UP_BUY_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("交易失败，密码错误次数超限，请半小时后重试");
            }
            return ServerResponse.createByErrorMsg("交易失败，密码输入错误");
        }
        return actualPurchase(user, stockCode, market, buyNum, buyType, lever, profitTarget, stopTarget, StockBuyTypeEnum.UP_BUY.getType(), payPwd);
    }

    /**
     * 大宗股票购买
     * @param id
     * @param request
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse dzBuy(Integer id,
                                String password,
                                Integer buyNum,
                                HttpServletRequest request,
                                String payPwd) {
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (user == null) {
            return ServerResponse.createByErrorMsg("交易失败，用户不存在");
        }

        // 获取大宗股票
        StockDz stockDz = stockDzService.getById(id);
        if (null == stockDz) {
            return ServerResponse.createByErrorMsg("交易失败，股票信息不存在");
        }

        Integer userId = user.getId();
        String stockCode = stockDz.getStockCode();
        String redisKey = "BUY_STOCK_" + userId + "_" + stockCode;

        String code = RedisShardedPoolUtils.get("BUY_STOCK_" + "_" + stockCode);
        if (StringUtils.isNotBlank(code)) {
            return ServerResponse.createByErrorMsg("操作失败，请勿重复提交");
        }
        RedisShardedPoolUtils.setEx(redisKey, stockCode, 10);

        // 校验当前日期是否在有效期内
        Date beforeStartTime = stockDz.getStartTime();
        DateTime aaBefore = new DateTime(beforeStartTime);

        Date beforeEndTime = stockDz.getEndTime();
        DateTime bbBefore = new DateTime(beforeEndTime);

        // 获取当前时间
        Date currentTime = new Date();
        DateTime time = new DateTime(currentTime);

        if (!time.after(aaBefore) || !time.before(bbBefore)) {
            return ServerResponse.createByErrorMsg("下单失败，该股票不在当前有效期内");
        }

        // 校验次数
        Integer time1 = stockDz.getTimes();

        if (!RedisShardedPoolUtils.exists("DZ:" + stockDz.getStockCode() + ":" + user.getId())) {
            RedisShardedPoolUtils.set("DZ:" + stockDz.getStockCode() + ":" + user.getId(), "0");
        }
        if (Integer.parseInt(RedisShardedPoolUtils.get("DZ:" + stockDz.getStockCode() + ":" + user.getId())) >= time1) {
            log.info("下单失败，大宗交易次数已经到达最高限制, 次数: " + time1);
            return ServerResponse.createByErrorMsg("交易失败，大宗交易次数已达上限");
        }

        // 校验密码
        if (!SymmetricCryptoUtil.encryptPassword(password).equals(stockDz.getPassword())) {
            boolean isLocked = iUserService.isLocked(User.DZ_BUY_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("交易失败，密码错误次数超限，请半小时后重试");
            }
            return ServerResponse.createByErrorMsg("交易失败，密码输入错误");
        }
        // 校验最低购买数量
        if (buyNum.intValue() < stockDz.getStockNum().intValue()) {
            return ServerResponse.createByErrorMsg("交易失败，购买数量低于最低要求");
        }

        String market = stockDz.getStockGid();
        Integer buyType = 0;
        Integer lever = 1;
        BigDecimal targetPrice = BigDecimal.ZERO;
        BigDecimal stopTarget = BigDecimal.ZERO;
        Integer stockType = StockBuyTypeEnum.DZ_BUY.getType();

        if (buyNum <= 0) {
            return ServerResponse.createByErrorMsg("购买数量必须大于0！");
        }

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("下单出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("系统错误，配置信息异常");
        }

        // 使用新版股票数据
        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
        stockQueryWrapper.eq("code", stockCode);
        stockQueryWrapper.eq("market", market);
        StStock stStock = stStockMapper.selectOne(stockQueryWrapper);
        if (null == stStock) {
            return ServerResponse.createByErrorMsg("下单失败，股票信息不存在！");
        }

        // 校验支付密码
        String userPayPwd = user.getPayPwd();
        if (StringUtils.isBlank(userPayPwd)) {
            return ServerResponse.createByErrorMsg("请先设置支付密码再进行交易！");
        }

        // 校验密码是否正确
        if (!SymmetricCryptoUtil.encryptPassword(payPwd).equals(userPayPwd)) {
            boolean isLocked = iUserService.isLocked(User.PAY_PWD_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("交易失败，支付密码已超过5次错误，请半小时后再试");
            }
            return ServerResponse.createByErrorMsg("交易失败，支付密码不正确，请重新输入！");
        }

        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();

        // 是否是盘前交易
        boolean isBefore = false;
        int beforeFlag = 0;
        StPremarketStock stPremarketStock = new StPremarketStock();

        if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
            return ServerResponse.createByErrorMsg("交易失败，请先完成实名认证");
        }

        log.info("用户 {} 下单，股票stockCode = {} ，数量 = {} , 方向 = {} , 杠杆 = {}", user.getId(), stockCode, buyNum, buyType, lever);
        if (siteProduct.getRealNameDisplay() && user.getIsLock() == 1) {
            return ServerResponse.createByErrorMsg("交易失败，账户已被锁定");
        }

        BigDecimal now_price;
        // 涨跌幅
        BigDecimal up;
        // 收盘价
        BigDecimal zsPrice;
        // 原始价格，美股就是美元，印度股就是卢比
        BigDecimal initPrice;
        // 股票名称
        String stockName;
        // 判断股票类型，1，市价购买 2，大宗股票 3，涨停板股票 4，挂单定时买入 5，新股转持仓
        if (StockBuyTypeEnum.DZ_BUY.getType().intValue() == stockType.intValue()) {
            QueryWrapper<StockDz> dzQueryWrapper = new QueryWrapper<>();
            dzQueryWrapper.eq("stock_code", stockCode);
            dzQueryWrapper.eq("stock_gid", market);
            StockDz dzStock = stockDzService.getOne(dzQueryWrapper);
            if (null == dzStock) {
                return ServerResponse.createByErrorMsg("交易失败，未找到股票信息，编码：" + stockCode + "，市场：" + market);
            }
            initPrice = dzStock.getDiscount();
            up = BigDecimal.ZERO;
            zsPrice = BigDecimal.ZERO;
            stockName = dzStock.getStockName();
        }
        else if((StockBuyTypeEnum.NEW_BUY.getType().intValue() == stockType.intValue())) {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("symbol", stockCode);
            queryWrapper.eq("exchange", market);
            StIpo ipo = stIpoService.getOne(queryWrapper);
            if (null == ipo) {
                return ServerResponse.createByErrorMsg("交易失败，没有IPO信息，编码：" + stockCode + "，市场：" + market);
            }
            initPrice = new BigDecimal(ipo.getIssuePrice());
            up = BigDecimal.ZERO;
            zsPrice = BigDecimal.ZERO;
            stockName = ipo.getName();
            stockCode = ipo.getSymbol();
        }
        else {
            // 查询该股票的实时价格
            StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(market, stockCode);
            if (null == tickerDetails) {
                return ServerResponse.createByErrorMsg("查询股票实时价格失败！【数据源异常】");
            }

            StockTickerListInfo tickerInfo = tickerDetails.getData();
            if (null == tickerInfo) {
                return ServerResponse.createByErrorMsg("查询股票实时价格失败！【数据解析异常】");
            }

            if (buyNum.intValue() < siteSetting.getBuyMinNum().intValue()) {
                return ServerResponse.createByErrorMsg("委托失败，购买数量不得低于最小交易量" + siteSetting.getBuyMinNum() + "股");
            }
            if (buyNum.intValue() > siteSetting.getBuyMaxNum().intValue()) {
                return ServerResponse.createByErrorMsg("委托失败，购买数量不得超过最大交易量" + siteSetting.getBuyMaxNum() + "股");
            }
            initPrice = tickerInfo.getPrice();
            up = tickerInfo.getUp();
            zsPrice = tickerInfo.getClose();
            stockName = tickerInfo.getName();
        }

        if (beforeFlag == 1) {
            // 这里要取第三方接口的历史实时K线里的数据, 这个值目前看是正确的
            String stockClose = getStockClose(market, stockCode);
            if (StringUtils.isNotBlank(stockClose)) {
                now_price = new BigDecimal(stockClose);
            }else {
                now_price = zsPrice;
            }
        } else if (beforeFlag == 2) {
            // 获取随机价格
            now_price = getRandomBigDecimal(stPremarketStock.getPrice(), stPremarketStock.getMaxPrice());
        } else {
            now_price = initPrice;
        }
        // 初识价格修改为盘前交易的价格
        initPrice = now_price;

        if (now_price.compareTo(BigDecimal.ZERO) == 0) {
            return ServerResponse.createByErrorMsg("当前报价为0，请稍后再试.");
        }

        double stock_crease = up.doubleValue();

        BigDecimal maxRisePercent = up;
        maxRisePercent = maxRisePercent.divide(new BigDecimal(100)).setScale(6, RoundingMode.HALF_UP);

        // 计算涨停价格  根据前收盘价和最大涨幅百分比计算涨停价
        BigDecimal ztPrice = zsPrice.multiply(maxRisePercent).add(zsPrice);
        ztPrice = ztPrice.setScale(6,  RoundingMode.HALF_UP);

        // 计算购买总额。这行代码将当前价格 now_price 乘以购买数量 buyNum，得到了购买总额 buy_amt。
        BigDecimal buy_amt = now_price.multiply(new BigDecimal(buyNum)).setScale(6, RoundingMode.HALF_UP);
        // 计算实际购买总额。
        BigDecimal buy_amt_autual = buy_amt;

        // 比较了实际购买总额 buy_amt_autual 与指定的最小购买金额 siteSetting.getBuyMinAmt() 这里的配置项是在后台管理系统配置的
        int compareInt = buy_amt_autual.compareTo(new BigDecimal(siteSetting.getBuyMinAmt()));
        if (compareInt == -1) {
            return ServerResponse.createByErrorMsg("委托失败，交易金额低于最低限额" + siteSetting.getBuyMinAmt() + "元");
        }

        /**
         * 用户可用金额
         */
        BigDecimal user_enable_amt = user.getEnableAmt();
        // 配资金额
        BigDecimal tradingAmount = user.getTradingAmount();

        // 检查实际购买总额是否超过了用户可用资金的最大允许比例 (可用资金 = 配资资金+用户现金)
        BigDecimal availableFunds = user_enable_amt.add(tradingAmount);

        BigDecimal max_buy_amt = availableFunds.multiply(siteSetting.getBuyMaxAmtPercent());
        int compareCwInt = buy_amt_autual.compareTo(max_buy_amt);
        if (compareCwInt == 1) {
            return ServerResponse.createByErrorMsg("委托失败，交易金额不可超过可用资金的" + siteSetting.getBuyMaxAmtPercent().multiply(new BigDecimal("100")) + "%");
        }

        log.info("用户id = {} 可用金额 = {} 实际购买金额 =  {}",user.getId(), availableFunds, buy_amt_autual);

        // 存储股票购买信息
        UserPosition userPosition = new UserPosition();
        userPosition.setInitPrice(initPrice);
        userPosition.setPositionType(user.getAccountType());
        userPosition.setPositionSn(KeyUtils.getUniqueKey());
        userPosition.setUserId(user.getId());
        userPosition.setNickName(user.getRealName());
        userPosition.setAgentId(user.getAgentId());
        userPosition.setStockCode(stockCode);
        userPosition.setStockName(stockName);
        userPosition.setStockGid(market);
        userPosition.setStockSpell(market);
        userPosition.setStockPlate(market);
        userPosition.setBuyOrderId(GeneratePosition.getPositionId());
        userPosition.setBuyOrderTime(new Date());
        userPosition.setBuyOrderPrice(now_price);
        userPosition.setOrderDirection((buyType == 0) ? "买涨" : "买跌");
        userPosition.setOrderNum(buyNum);
        if (SystemVersionEnum.india.name().equals(active)) {
            if((StockBuyTypeEnum.NEW_BUY.getType().intValue() == stockType.intValue())){
                UserStockSubscribe userStockSubscribe = userStockSubscribeMapper.load(Integer.parseInt(stockCode));
                userPosition.setOrderNum(userStockSubscribe.getApplyNumber());
            }
        }
        userPosition.setIsLock(0);
        userPosition.setOrderLever(lever);
        userPosition.setOrderTotalPrice(buy_amt);

        //递延费特殊处理
        BigDecimal stayFee = userPosition.getOrderTotalPrice().multiply(siteSetting.getStayFee());
        userPosition.setOrderStayFee(BigDecimal.ZERO);
        userPosition.setOrderStayDays(0);
        // 印花税
        BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(6, RoundingMode.HALF_UP);
        log.info("用户id = {} 购买印花税（配资后总资金 * 百分比） = {}", user.getId(), buy_yhs_amt);
        userPosition.setOrderSpread(BigDecimal.ZERO);

        // 点差费
        SiteSpread siteSpread = iSiteSpreadService.findSpreadRateOne(new BigDecimal(stock_crease), buy_amt, stockCode, now_price);
        BigDecimal spread_rate_amt = BigDecimal.ZERO;
        if (siteSpread != null) {
            spread_rate_amt = buy_amt.multiply(siteSpread.getSpreadRate()).setScale(6, RoundingMode.HALF_UP);
            log.info("用户id = {} 购买点差费（配资后总资金 * 百分比{}） = {}",user.getId(), siteSpread.getSpreadRate(), spread_rate_amt);
        } else {
            log.info("用户id = {} 购买点差费（配资后总资金 * 百分比{}） = {}", "设置异常",user.getId(), spread_rate_amt);
        }

        userPosition.setSpreadRatePrice(BigDecimal.ZERO);

        // 手续费
        BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(6, RoundingMode.HALF_UP);
        log.info("用户id = {} 购买手续费（配资后总资金 * 百分比） = {}", user.getId(), buy_fee_amt);
        userPosition.setOrderFee(buy_fee_amt);
        // 设置盈亏
        BigDecimal profit_and_lose = BigDecimal.ZERO;
        // 设置浮动盈亏 初始时是0
        userPosition.setProfitAndLose(profit_and_lose);

        // 设置总盈亏  包括手续费 印花税 点差费  这块在购买的时候已经扣除了
        BigDecimal all_profit_and_lose = profit_and_lose.subtract(buy_fee_amt);
        userPosition.setAllProfitAndLose(all_profit_and_lose);

        // 购买金额 = 当前价格 * 数量 + 手续费
        buy_amt_autual = buy_amt_autual.add(buy_fee_amt);

        // 判断用户是否已经存在该股票
        UserPosition position = this.userPositionMapper.findUserPositionByCode(user.getId(), stockCode);
        Integer oldOrderNum = 0;
        // 如果已经存在该股票，那么需要进行叠加，价格取平均值
        if (null != position) {
            oldOrderNum = position.getOrderNum();
            position.setInitPrice(position.getInitPrice().add(userPosition.getInitPrice()).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP));
            position.setBuyOrderPrice(position.getBuyOrderPrice().add(userPosition.getBuyOrderPrice()).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP));
            position.setOrderNum(userPosition.getOrderNum()+position.getOrderNum());
            BigDecimal oldProfitTargetPrice = userPosition.getProfitTargetPrice() != null ? userPosition.getProfitTargetPrice() : BigDecimal.ZERO;
            BigDecimal currProfitTargetPrice = position.getProfitTargetPrice() != null ? position.getProfitTargetPrice() : BigDecimal.ZERO;
            position.setProfitTargetPrice(oldProfitTargetPrice.add(currProfitTargetPrice));
            position.setOrderTotalPrice(position.getOrderTotalPrice().add(userPosition.getOrderTotalPrice()));
            position.setOrderFee(position.getOrderFee().add(userPosition.getOrderFee()));
            position.setOrderSpread(position.getOrderSpread().add(userPosition.getOrderSpread()));
            position.setOrderStayFee(position.getOrderStayFee().add(userPosition.getOrderStayFee()));
            position.setProfitAndLose(position.getProfitAndLose().add(userPosition.getProfitAndLose()));
            position.setAllProfitAndLose(position.getAllProfitAndLose().add(userPosition.getAllProfitAndLose()));
            position.setSpreadRatePrice(position.getSpreadRatePrice().add(userPosition.getSpreadRatePrice()));
            this.userPositionMapper.updateByPrimaryKey(position);
            userPosition.setId(position.getId());
            userPosition.setBuyOrderId(position.getBuyOrderId());
        } else {

            List<UserPosition> list = userPositionMapper.selectListByUserIdAndCode(userId, stockCode);
            if (list != null && list.size() > 0) {
                return ServerResponse.createByErrorMsg("您已持有该股票，请勿重复购买！");
            }

            this.userPositionMapper.insert(userPosition);
            userPosition.setId(userPosition.getId());
        }

        // 记录购买详情
        int detailId = insertPositionDetail(userPosition, oldOrderNum, 1, stockType);
        if (detailId > 0) {
            boolean isBuy = false;

            // 如果是挂单买入，则需要将冻结资金的钱回到配资或者可用资金中之后再进行付款，否则会重复扣款
            if (StockBuyTypeEnum.PENDING_BUY.getType().equals(stockType)) {
                // 将用户设置的目标价格的钱退回到配资或者可用余额, 将冻结的金额减去
                // 需要退还的金额 = 目标价格 * 购买数量
                BigDecimal rockAmount = targetPrice.multiply(new BigDecimal(buyNum));
                BigDecimal enableAmt = user.getEnableAmt();
                enableAmt = enableAmt.add(rockAmount);
                user.setEnableAmt(enableAmt);
                BigDecimal djzj = user.getDjzj();
                djzj = djzj.subtract(rockAmount);
                if (djzj.compareTo(BigDecimal.ZERO) <= 0) {
                    djzj = new BigDecimal(BigInteger.ZERO);
                }
                user.setDjzj(djzj);

                User updateUser = new User();
                updateUser.setId(user.getId());
                updateUser.setDjzj(djzj);
                updateUser.setEnableAmt(enableAmt);
                userMapper.updateByPrimaryKeySelective(updateUser);
                // 实际扣款方法
                isBuy = updateUserAccount(user, buy_amt_autual);
            } else if (StockBuyTypeEnum.NEW_BUY.getType().equals(stockType)) {
                // 新股转持仓 需要查询用户是否有补缴信息


                // 如果是新股申购，则需要先将金额退回到可用余额，并且冻结金额扣除
                BigDecimal enableAmt = user.getEnableAmt();
                enableAmt = enableAmt.add(buy_amt);
                user.setEnableAmt(enableAmt);

                BigDecimal djzj = user.getDjzj();
                djzj = djzj.subtract(buy_amt);
                if (djzj.compareTo(BigDecimal.ZERO) <= 0) {
                    djzj = new BigDecimal(BigInteger.ZERO);
                }
                user.setDjzj(djzj);

                User updateUser = new User();
                updateUser.setId(user.getId());
                updateUser.setDjzj(djzj);
                updateUser.setEnableAmt(enableAmt);
                userMapper.updateByPrimaryKeySelective(updateUser);
            }else{
                // 实际扣款方法
                isBuy = updateUserAccount(user, buy_amt_autual);
            }


            if (!isBuy) {
                log.info("用户ID："+user.getId()+"交易下单, 修改用户金额出错: 用户配资金额：" + user.getTradingAmount() + "; 可用金额： " + user.getEnableAmt() + "; 下单金额： " + buy_amt_autual + ";");
                throw new IllegalArgumentException("用户委托交易时发生资金变更异常，请检查账户余额！");
            }

            User currentUser = userMapper.selectById(user.getId());
            // 存储资金记录
            UserCashDetail ucd = new UserCashDetail();
            ucd.setPositionId(userPosition.getId());
            ucd.setAgentId(user.getAgentId());
            ucd.setAgentName(user.getAgentName());
            ucd.setUserId(user.getId());
            ucd.setUserName(user.getRealName());
            ucd.setDeType("buy stock");
            ucd.setDeAmt(buy_amt_autual.multiply(new BigDecimal("-1")));
            ucd.setDeSummary(user.getNickName() + " 买入股票，" + userPosition.getStockCode() + "/" + userPosition.getStockName()
                    + "，实际交易金额：" + buy_amt_autual + "，手续费：" + buy_fee_amt + "，可用资金: " + currentUser.getEnableAmt()
                    + "，冻结资金: " + currentUser.getDjzj() + "，配资金额: " + currentUser.getTradingAmount());
            ucd.setAddTime(new Date());
            ucd.setIsRead(0);

            int insertSxfCount = this.userCashDetailMapper.insert(ucd);
            if (insertSxfCount > 0) {
                log.info("【用户: {} 买入股票】保存明细记录成功", user.getId());
                // 买入股票赠送积分
                bonusPoints(user.getId(), buy_amt_autual, StIntegralTask.TASK_TYPE_BUY_STOCKS);
            } else {
                log.error("用户: {} 买入股票】保存明细记录出错", user.getId());
            }

            log.info("【用户: {} 交易下单】保存持仓记录成功", user.getId());

            // 购买时发送邮件提醒
            if(SystemVersionEnum.global.name().equals(active)) {
                UserPositionDetail positionDetail = userPositionDetailMapper.selectById(detailId);
                sendHTMLMail.sendTradingBehaviorEmail(user, positionDetail);
            }
        } else {
            log.error("用户: {} 交易下单】保存持仓记录出错", user.getId());
            return ServerResponse.createByErrorMsg("用户("+user.getId()+")交易委托失败，持仓记录保存异常！");
        }
        // 如果是盘前交易，那么需要计数
        if (isBefore) {
            RedisShardedPoolUtils.incr("before:" + stPremarketStock.getId() + ":" + user.getId());
        }
        // 大宗交易股票，需要计数
        if (StockBuyTypeEnum.DZ_BUY.getType().intValue() == stockType.intValue()) {
            RedisShardedPoolUtils.incr("DZ:" + stockCode + ":" + user.getId());
        }
        return ServerResponse.createBySuccessMsg("订单交易成功！");
    }




    /**
     * 实际购买方法
     * @param user
     * @param stockCode
     * @param buyNum
     * @param buyType
     * @param lever
     * @param stopTarget
     * @param stockType
     * @return
     */
    private ServerResponse actualPurchase (User user,
                                           String stockCode,
                                           String market,
                                           Integer buyNum,
                                           Integer buyType,
                                           Integer lever,
                                           BigDecimal targetPrice,
                                           BigDecimal stopTarget,
                                           Integer stockType,
                                           String payPwd){

        // 判断购买数量
        if (buyNum <= 0) {
            return ServerResponse.createByErrorMsg("采购数量必须大于0！");
        }
        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("下单出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("下单出错，网站设置表不存在.");
        }

        // 使用新版股票数据
        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
        stockQueryWrapper.eq("code", stockCode);
        stockQueryWrapper.eq("market", market);
        StStock stStock = stStockMapper.selectOne(stockQueryWrapper);
        if (null == stStock) {
            return ServerResponse.createByErrorMsg("订单失败，股票不存在！");
        }

        // 校验支付密码
        String userPayPwd = user.getPayPwd();
        if (StringUtils.isBlank(userPayPwd)) {
            return ServerResponse.createByErrorMsg("您尚未设置支付密码。购买前请设置付款密码!");
        }

        // 校验密码是否正确
        if (!SymmetricCryptoUtil.encryptPassword(payPwd).equals(userPayPwd)) {
            boolean isLocked = iUserService.isLocked(User.PAY_PWD_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("购买失败，密码已超过5次。请等待半小时后再购买.");
            }
            return ServerResponse.createByErrorMsg("购买失败，您输入的密码不正确，请重新输入!");
        }

        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();

        // 是否是盘前交易
        boolean isBefore = false;
        int beforeFlag = 0;
        StPremarketStock stPremarketStock = new StPremarketStock();
        // 如果不是大宗，需要判断交易时间段
        if (StockBuyTypeEnum.DZ_BUY.getType().intValue() != stockType.intValue()) {
            // 判断是否在交易时间内
            boolean marketHours = BuyAndSellUtils.UsStockMarketHours(market, siteSetting);
            if (!marketHours) {
                // 如果不在交易时间内，那么查询盘前交易配置
                List<StPremarketStock> list = stPremarketStockService.listByCodeAndMarket(stockCode, market);
                if (CollectionUtils.isEmpty(list)) {
                    log.info("下单失败，不在交易时间内, 市场: " + market);
                    return ServerResponse.createByErrorMsg("购买失败，不在交易期内.");
                }
                // 获取当前时间
                Date currentTime = new Date();
                DateTime time = new DateTime(currentTime);
                for (StPremarketStock stock : list) {
                    // 盘前交易1--开始时间
                    Date beforeStartTime = stock.getBeforeStartTime();
                    DateTime aaBefore = new DateTime(beforeStartTime);
                    // 盘前交易1--结束时间
                    Date beforeEndTime = stock.getBeforeEndTime();
                    DateTime bbBefore = new DateTime(beforeEndTime);
                    if(time.after(aaBefore) && time.before(bbBefore)) {
                        beforeFlag = 1;
                        BeanUtils.copyProperties(stock, stPremarketStock);
                        break;
                    }
                    // 盘前交易2--开始时间
                    Date startTime = stock.getStartTime();
                    DateTime aa = new DateTime(startTime);
                    // 盘前交易2--结束时间
                    Date endTime = stock.getEndTime();
                    DateTime bb = new DateTime(endTime);
                    if(time.after(aa) && time.before(bb)){
                        beforeFlag = 2;
                        BeanUtils.copyProperties(stock, stPremarketStock);
                        break;
                    }
                }
                if (beforeFlag == 0) {
                    log.info("下单失败，不再盘前交易配置所设置的时间段内, market: " + market);
                    return ServerResponse.createByErrorMsg("购买失败，在设定时间内不再进行盘前交易配置。系统时间：" + time.toString("yyyy-MM-dd HH:mm:ss"));
                }
                if (!RedisShardedPoolUtils.exists("before:" + stPremarketStock.getId() + ":" + user.getId())) {
                    RedisShardedPoolUtils.set("before:" + stPremarketStock.getId() + ":" + user.getId(), "0");
                }
                if (Integer.parseInt(RedisShardedPoolUtils.get("before:" + stPremarketStock.getId() + ":" + user.getId())) >= stPremarketStock.getTimes()) {
                    log.info("下单失败，盘前交易次数已经到达最高限制, 次数: " + stPremarketStock.getTimes());
                    return ServerResponse.createByErrorMsg("购买失败，盘前交易数量已达到最大限额.");
                }
                isBefore = true;
            }
            // 判断是否在后台设置中，如果在，则不允许购买
            if (isHoliday()) {
                return ServerResponse.createByErrorMsg("周末或节假日不能交易.");
            }
        }

        if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
            return ServerResponse.createByErrorMsg("订单失败，请先实名认证.");
        }

        log.info("用户 {} 下单，股票stockCode = {} ，数量 = {} , 方向 = {} , 杠杆 = {}", user.getId(), stockCode, buyNum, buyType, lever);
        if (siteProduct.getRealNameDisplay() && user.getIsLock() == 1) {
            return ServerResponse.createByErrorMsg("订单失败且帐户锁定");
        }

        BigDecimal now_price;
        // 涨跌幅
        BigDecimal up;
        // 收盘价
        BigDecimal zsPrice;
        // 原始价格，美股就是美元，印度股就是卢比
        BigDecimal initPrice;
        // 股票名称
        String stockName;
        // 判断股票类型，1，市价购买 2，大宗股票 3，涨停板股票 4，挂单定时买入 5，新股转持仓
        if (StockBuyTypeEnum.DZ_BUY.getType().intValue() == stockType.intValue()) {
            QueryWrapper<StockDz> dzQueryWrapper = new QueryWrapper<>();
            dzQueryWrapper.eq("stock_code", stockCode);
            dzQueryWrapper.eq("stock_gid", market);
            StockDz dzStock = stockDzService.getOne(dzQueryWrapper);
            if (null == dzStock) {
                return ServerResponse.createByErrorMsg("订单失败, 没有大宗股票信息");
            }
            initPrice = dzStock.getDiscount();
            up = BigDecimal.ZERO;
            zsPrice = BigDecimal.ZERO;
            stockName = dzStock.getStockName();
        } else if((StockBuyTypeEnum.NEW_BUY.getType().intValue() == stockType.intValue())) {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("symbol", stockCode);
            queryWrapper.eq("exchange", market);
            StIpo ipo = stIpoService.getOne(queryWrapper);
            if (null == ipo) {
                return ServerResponse.createByErrorMsg("订单失败，没有IPO信息");
            }
            initPrice = new BigDecimal(ipo.getIssuePrice());
            up = BigDecimal.ZERO;
            zsPrice = BigDecimal.ZERO;
            stockName = ipo.getName();
            stockCode = ipo.getSymbol();
        } else {
            // 查询该股票的实时价格
            StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(market, stockCode);
            if (null == tickerDetails) {
                return ServerResponse.createByErrorMsg("查询股票实时价格失败！[股票详情]");
            }

            StockTickerListInfo tickerInfo = tickerDetails.getData();
            if (null == tickerInfo) {
                return ServerResponse.createByErrorMsg("查询股票实时价格失败！[tickerInfo]");
            }

            if (buyNum.intValue() < siteSetting.getBuyMinNum().intValue()) {
                return ServerResponse.createByErrorMsg("订单失败，购买数量少于 " + siteSetting.getBuyMinNum() + "股");
            }
            if (buyNum.intValue() > siteSetting.getBuyMaxNum().intValue()) {
                return ServerResponse.createByErrorMsg("订单失败，购买数量大于" + siteSetting.getBuyMaxNum() + "股");
            }
            initPrice = tickerInfo.getPrice();
            up = tickerInfo.getUp();
            zsPrice = tickerInfo.getClose();
            stockName = tickerInfo.getName();
        }

        if (beforeFlag == 1) {
            // 这里要取第三方接口的历史实时K线里的数据, 这个值目前看是正确的
            String stockClose = getStockClose(market, stockCode);
            if (StringUtils.isNotBlank(stockClose)) {
                now_price = new BigDecimal(stockClose);
            }else {
                now_price = zsPrice;
            }
        } else if (beforeFlag == 2) {
            // 获取随机价格
            now_price = getRandomBigDecimal(stPremarketStock.getPrice(), stPremarketStock.getMaxPrice());
        } else {
            now_price = initPrice;
        }
        // 初识价格修改为盘前交易的价格
        initPrice = now_price;

        if (now_price.compareTo(BigDecimal.ZERO) == 0) {
            return ServerResponse.createByErrorMsg("当前报价为0，请稍后再试");
        }

        double stock_crease = up.doubleValue();

        BigDecimal maxRisePercent = up;
        maxRisePercent = maxRisePercent.divide(new BigDecimal(100)).setScale(6, RoundingMode.HALF_UP);

        // 计算涨停价格  根据前收盘价和最大涨幅百分比计算涨停价
        BigDecimal ztPrice = zsPrice.multiply(maxRisePercent).add(zsPrice);
        ztPrice = ztPrice.setScale(6,  RoundingMode.HALF_UP);

        // 计算购买总额。这行代码将当前价格 now_price 乘以购买数量 buyNum，得到了购买总额 buy_amt。
        BigDecimal buy_amt = now_price.multiply(new BigDecimal(buyNum)).setScale(6, RoundingMode.HALF_UP);
        // 计算实际购买总额。
        BigDecimal buy_amt_autual = buy_amt;

        // 比较了实际购买总额 buy_amt_autual 与指定的最小购买金额 siteSetting.getBuyMinAmt() 这里的配置项是在后台管理系统配置的
        int compareInt = buy_amt_autual.compareTo(new BigDecimal(siteSetting.getBuyMinAmt()));
        if (compareInt == -1) {
            return ServerResponse.createByErrorMsg("订单失败，购买金额不足 " + siteSetting.getBuyMinAmt() + "元");
        }

        /**
         * 用户可用金额
         */
        BigDecimal user_enable_amt = user.getEnableAmt();
        // 配资金额
        BigDecimal tradingAmount = user.getTradingAmount();

        // 检查实际购买总额是否超过了用户可用资金的最大允许比例 (可用资金 = 配资资金+用户现金)
        BigDecimal availableFunds = user_enable_amt.add(tradingAmount);

        BigDecimal max_buy_amt = availableFunds.multiply(siteSetting.getBuyMaxAmtPercent());
        int compareCwInt = buy_amt_autual.compareTo(max_buy_amt);
        if (compareCwInt == 1) {
            return ServerResponse.createByErrorMsg("订单失败，不能超过可用资金" + siteSetting.getBuyMaxAmtPercent().multiply(new BigDecimal("100")) + "%");
        }

        log.info("用户id = {} 可用金额 = {} 实际购买金额 =  {}",user.getId(), availableFunds, buy_amt_autual);

        // 存储股票购买信息
        UserPosition userPosition = new UserPosition();
//        if (targetPrice != null && targetPrice.compareTo(BigDecimal.ZERO) > 0) {
//            userPosition.setProfitTargetPrice(targetPrice);
//        }
//        if (stopTarget != null && stopTarget.compareTo(BigDecimal.ZERO) > 0) {
//            userPosition.setStopTargetPrice(stopTarget);
//        }
        userPosition.setInitPrice(initPrice);
        userPosition.setPositionType(user.getAccountType());
        userPosition.setPositionSn(KeyUtils.getUniqueKey());
        userPosition.setUserId(user.getId());
        userPosition.setNickName(user.getRealName());
        userPosition.setAgentId(user.getAgentId());
        userPosition.setStockCode(stockCode);
        userPosition.setStockName(stockName);
        userPosition.setStockGid(market);
        userPosition.setStockSpell(market);
        userPosition.setStockPlate(market);
        userPosition.setBuyOrderId(GeneratePosition.getPositionId());
        userPosition.setBuyOrderTime(new Date());
        userPosition.setBuyOrderPrice(now_price);
        userPosition.setOrderDirection((buyType == 0) ? "买涨" : "买跌");
        userPosition.setOrderNum(buyNum);
        if((StockBuyTypeEnum.NEW_BUY.getType().intValue() == stockType.intValue())){
            UserStockSubscribe userStockSubscribe = userStockSubscribeMapper.load(Integer.parseInt(stockCode));
            if (null != userStockSubscribe) {
                userPosition.setOrderNum(userStockSubscribe.getApplyNumber());
            }
        }
        userPosition.setIsLock(0);
        userPosition.setOrderLever(lever);
        userPosition.setOrderTotalPrice(buy_amt);

        //递延费特殊处理
        BigDecimal stayFee = userPosition.getOrderTotalPrice().multiply(siteSetting.getStayFee());
        userPosition.setOrderStayFee(BigDecimal.ZERO);
        userPosition.setOrderStayDays(0);
        // 印花税
        BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(6, RoundingMode.HALF_UP);
        log.info("用户id = {} 购买印花税（配资后总资金 * 百分比） = {}", user.getId(), buy_yhs_amt);
        userPosition.setOrderSpread(BigDecimal.ZERO);
        // 点差费
        SiteSpread siteSpread = iSiteSpreadService.findSpreadRateOne(new BigDecimal(stock_crease), buy_amt, stockCode, now_price);
        BigDecimal spread_rate_amt = BigDecimal.ZERO;
        if (siteSpread != null) {
            spread_rate_amt = buy_amt.multiply(siteSpread.getSpreadRate()).setScale(6, RoundingMode.HALF_UP);
            log.info("用户id = {} 购买点差费（配资后总资金 * 百分比{}） = {}",user.getId(), siteSpread.getSpreadRate(), spread_rate_amt);
        } else {
            log.info("用户id = {} 购买点差费（配资后总资金 * 百分比{}） = {}", "设置异常",user.getId(), spread_rate_amt);
        }
        userPosition.setSpreadRatePrice(BigDecimal.ZERO);

        // 手续费
        BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(6, RoundingMode.HALF_UP);
        log.info("用户id = {} 购买手续费（配资后总资金 * 百分比） = {}", user.getId(), buy_fee_amt);
        userPosition.setOrderFee(buy_fee_amt);
        // 设置盈亏
        BigDecimal profit_and_lose = BigDecimal.ZERO;
        // 设置浮动盈亏 初始时是0
        userPosition.setProfitAndLose(profit_and_lose);

        // 设置总盈亏  包括手续费 印花税 点差费  这块在购买的时候已经扣除了
        BigDecimal all_profit_and_lose = profit_and_lose.subtract(buy_fee_amt);
        userPosition.setAllProfitAndLose(all_profit_and_lose);

        // 购买金额 = 当前价格 * 数量 + 手续费
        buy_amt_autual = buy_amt_autual.add(buy_fee_amt);

        // 判断用户是否已经存在该股票
        UserPosition position = this.userPositionMapper.findUserPositionByCode(user.getId(), stockCode);
        Integer oldOrderNum = 0;
        // 如果已经存在该股票，那么需要进行叠加，价格取平均值
        if (null != position) {
            oldOrderNum = position.getOrderNum();
            position.setInitPrice(position.getInitPrice().add(userPosition.getInitPrice()).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP));
            position.setBuyOrderPrice(position.getBuyOrderPrice().add(userPosition.getBuyOrderPrice()).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP));
            position.setOrderNum(userPosition.getOrderNum()+position.getOrderNum());
            BigDecimal oldProfitTargetPrice = userPosition.getProfitTargetPrice() != null ? userPosition.getProfitTargetPrice() : BigDecimal.ZERO;
            BigDecimal currProfitTargetPrice = position.getProfitTargetPrice() != null ? position.getProfitTargetPrice() : BigDecimal.ZERO;
            position.setProfitTargetPrice(oldProfitTargetPrice.add(currProfitTargetPrice));
            position.setOrderTotalPrice(position.getOrderTotalPrice().add(userPosition.getOrderTotalPrice()));
            position.setOrderFee(position.getOrderFee().add(userPosition.getOrderFee()));
            position.setOrderSpread(position.getOrderSpread().add(userPosition.getOrderSpread()));
            position.setOrderStayFee(position.getOrderStayFee().add(userPosition.getOrderStayFee()));
            position.setProfitAndLose(position.getProfitAndLose().add(userPosition.getProfitAndLose()));
            position.setAllProfitAndLose(position.getAllProfitAndLose().add(userPosition.getAllProfitAndLose()));
            position.setSpreadRatePrice(position.getSpreadRatePrice().add(userPosition.getSpreadRatePrice()));
            this.userPositionMapper.updateByPrimaryKey(position);
            userPosition.setId(position.getId());
            userPosition.setBuyOrderId(position.getBuyOrderId());
        } else {
            this.userPositionMapper.insert(userPosition);
            userPosition.setId(userPosition.getId());
        }

        // 记录购买详情
        int detailId = insertPositionDetail(userPosition, oldOrderNum, 1, stockType);
        if (detailId > 0) {
            boolean isBuy = false;

            // 如果是挂单买入，则需要将冻结资金的钱回到配资或者可用资金中之后再进行付款，否则会重复扣款
            if (StockBuyTypeEnum.PENDING_BUY.getType().equals(stockType)) {
                // 将用户设置的目标价格的钱退回到配资或者可用余额, 将冻结的金额减去
                // 需要退还的金额 = 目标价格 * 购买数量
                BigDecimal rockAmount = targetPrice.multiply(new BigDecimal(buyNum));
                BigDecimal enableAmt = user.getEnableAmt();
                enableAmt = enableAmt.add(rockAmount);
                user.setEnableAmt(enableAmt);
                BigDecimal djzj = user.getDjzj();
                djzj = djzj.subtract(rockAmount);
                if (djzj.compareTo(BigDecimal.ZERO) <= 0) {
                    djzj = new BigDecimal(BigInteger.ZERO);
                }
                user.setDjzj(djzj);

                User updateUser = new User();
                updateUser.setId(user.getId());
                updateUser.setDjzj(djzj);
                updateUser.setEnableAmt(enableAmt);
                userMapper.updateByPrimaryKeySelective(updateUser);
                // 实际扣款方法
                isBuy = updateUserAccount(user, buy_amt_autual);
            } else if (StockBuyTypeEnum.NEW_BUY.getType().equals(stockType)) {
                // 新股转持仓 需要查询用户是否有补缴信息


                // 如果是新股申购，则需要先将金额退回到可用余额，并且冻结金额扣除
                BigDecimal enableAmt = user.getEnableAmt();
                enableAmt = enableAmt.add(buy_amt);
                user.setEnableAmt(enableAmt);

                BigDecimal djzj = user.getDjzj();
                djzj = djzj.subtract(buy_amt);
                if (djzj.compareTo(BigDecimal.ZERO) <= 0) {
                    djzj = new BigDecimal(BigInteger.ZERO);
                }
                user.setDjzj(djzj);

                User updateUser = new User();
                updateUser.setId(user.getId());
                updateUser.setDjzj(djzj);
                updateUser.setEnableAmt(enableAmt);
                userMapper.updateByPrimaryKeySelective(updateUser);
            }else{
                // 实际扣款方法
                isBuy = updateUserAccount(user, buy_amt_autual);
            }


            if (!isBuy) {
                log.error("用户交易下单, 修改用户金额出错: 用户配资金额：" + user.getTradingAmount() + "; 可用金额： " + user.getEnableAmt() + "; 下单金额： " + buy_amt_autual + "; 用户ID：" + user.getId());
                throw new IllegalArgumentException("用户交易下单并修改用户金额时出现错误.");
            }

            User currentUser = userMapper.selectById(user.getId());

            // 存储资金记录
            UserCashDetail ucd = new UserCashDetail();
            ucd.setPositionId(userPosition.getId());
            ucd.setAgentId(user.getAgentId());
            ucd.setAgentName(user.getAgentName());
            ucd.setUserId(user.getId());
            ucd.setUserName(user.getRealName());
            ucd.setDeType("购买股票");
            ucd.setDeAmt(buy_amt_autual.multiply(new BigDecimal("-1")));
            ucd.setDeSummary(user.getNickName() + " 购买股票，股票编码：" + userPosition.getStockCode() + "/" + userPosition.getStockName()
                     + ", 实际购买金额：" + buy_amt_autual + ", 购买手续费：" + buy_fee_amt + ", 可用资金: " + currentUser.getEnableAmt() + ", 冻结资金: "
                    + currentUser.getDjzj() + ", 交易金额: " + currentUser.getTradingAmount());

            ucd.setAddTime(new Date());
            ucd.setIsRead(Integer.valueOf(0));

            int insertSxfCount = this.userCashDetailMapper.insert(ucd);
            if (insertSxfCount > 0) {
                log.info("【用户买入股票】保存明细记录成功");
                // 买入股票赠送积分
                bonusPoints(user.getId(), buy_amt_autual, StIntegralTask.TASK_TYPE_BUY_STOCKS);
            } else {
                log.error("用户买入股票】保存明细记录出错");
            }

            log.info("【用户交易下单】保存持仓记录成功");
            // 购买时发送邮件提醒
            if(SystemVersionEnum.global.name().equals(active)) {
                UserPositionDetail positionDetail = userPositionDetailMapper.selectById(detailId);
                sendHTMLMail.sendTradingBehaviorEmail(user, positionDetail);
            }
        } else {
            log.error("用户交易下单，保存持仓记录出错");
            return ServerResponse.createByErrorMsg("用户交易下单，保存持仓记录出错");
        }
        // 如果是盘前交易，那么需要计数
        if (isBefore) {
            RedisShardedPoolUtils.incr("before:" + stPremarketStock.getId() + ":" + user.getId());
        }
        // 大宗交易，需要计数
        if (StockBuyTypeEnum.DZ_BUY.getType().intValue() == stockType.intValue()) {
            RedisShardedPoolUtils.incr("DZ:" + stockCode + ":" + user.getId());

        }
        return ServerResponse.createBySuccessMsg("订单交易成功.");
    }

    // 购买赠送积分方法
    private void bonusPoints(Integer userId, BigDecimal amount, String taskType){
        StIntegralTask task = integralTaskMapper.queryTaskByType(taskType, amount);

        // 查询出该类型配置的最大值和最小值 然后判断充值金额满足  例如 充值1 元  最小值是10元 那么就不需要赠送  充值100  最大值是10 那么就需要按照最大值来赠送
        if (null == task) {
            StIntegralTask maxTask = integralTaskMapper.queryMaxByType(taskType);
            if (null != maxTask) {
                Integer maxNum = maxTask.getMaxNum();
                if(maxNum < amount.intValue()){
                    // 按照最大值赠送
                    Integer integral = maxTask.getIntegral();
                    iUserService.updateUserIntegral(userId, integral, taskType, true, maxTask.getId());
                }
            }
        }
        else {
            Integer integral = task.getIntegral();
            iUserService.updateUserIntegral(userId, integral, taskType, true, task.getId());
        }
    }

    private boolean isHoliday(){
        // 判断是否在后台设置中，如果在，则不允许购买
        AtomicBoolean isHoliday = new AtomicBoolean(false);
        List<StHolidays> holidaysList = stHolidaysMapper.selectList(null);
        if (CollectionUtils.isNotEmpty(holidaysList)) {
            holidaysList.forEach(stHolidays -> {
                Date date = stHolidays.getHoliday();
                Date currDate = new Date();
                if (DateUtils.equals(date, currDate, "yyyy-MM-dd")) {
                    isHoliday.set(true);
                }
            });
        }
        return isHoliday.get();
    }

    /**
     * 修改股票购买扣款路径  先扣配资账户(不包括保证金) 不够了 再扣可用资金
     * @param user
     * @param buyAmount
     * @return
     */
    @Override
    public boolean updateUserAccount(User user, BigDecimal buyAmount) {

        // 判断配资是否大于支付金额  配资金额首先要减去冻结金额(配资保证金 + 挂单金额)
        BigDecimal tradingAmount = user.getTradingAmount();

        // 配资账户中扣除购买金额
        tradingAmount = tradingAmount.subtract(buyAmount);

        if (tradingAmount.compareTo(BigDecimal.ZERO) == 0) {
            // 扣除配置的钱后 配资账户为0 再去扣除用户余额的钱 没有报错
            iUserService.updateTradingAmount(user.getId(),  new BigDecimal("0"), null);
            return true;
        }

        if (tradingAmount.compareTo(BigDecimal.ZERO) < 0) {
            // 扣除配资的钱后 配资账户为0 再去扣除用户余额的钱 没有报错
            BigDecimal enableAmt = user.getEnableAmt();
            // 这里使用加法  是因为配资的钱已经是负数了
            enableAmt = enableAmt.add(tradingAmount);

            // 如果扣完配置的钱 还不够 继续扣余额的钱  也还不够  那么就报错
            if (enableAmt.compareTo(BigDecimal.ZERO) < 0) {
                return false;
            }

            iUserService.updateTradingAmount(user.getId(),  new BigDecimal("0"), enableAmt);
            return true;
        }

        iUserService.updateTradingAmount(user.getId(),  tradingAmount, null);
        return true;
    }


    /**
     * 保存买入卖出数据
     * @param userPosition
     * @param type
     */
    public int insertPositionDetail(UserPosition userPosition, Integer orderNum, Integer type, Integer stockType) {
        UserPositionDetail userPositionDetail = new UserPositionDetail();
        userPositionDetail.setPositionId(userPosition.getId());
        userPositionDetail.setUserId(userPosition.getUserId());
        userPositionDetail.setStockName(userPosition.getStockName());
        userPositionDetail.setStockCode(userPosition.getStockCode());
        userPositionDetail.setStockGid(userPosition.getStockGid());
        userPositionDetail.setStockSpell(userPosition.getStockSpell());
        userPositionDetail.setType(type);
        userPositionDetail.setOrderId(GeneratePosition.getPositionId());
        if (type == 1) {// 买入
            userPositionDetail.setParentOrderId(userPosition.getBuyOrderId());
            userPositionDetail.setOrderTime(new Date());
            userPositionDetail.setOrderPrice(userPosition.getBuyOrderPrice());
            userPositionDetail.setOrderNum(userPosition.getOrderNum()); // 这里买入和卖出的值取的不一样
            userPositionDetail.setLastNum(orderNum + userPosition.getOrderNum());
            // 计算总价格
            userPositionDetail.setOrderTotalPrice(new BigDecimal(userPosition.getOrderNum()).multiply(userPosition.getBuyOrderPrice()).setScale(6, BigDecimal.ROUND_HALF_UP));
        } else {
            userPositionDetail.setParentOrderId(userPosition.getSellOrderId());
            userPositionDetail.setOrderTime(new Date());
            userPositionDetail.setOrderPrice(userPosition.getSellOrderPrice());
            userPositionDetail.setOrderNum(orderNum);
            userPositionDetail.setLastNum(userPosition.getOrderNum() - orderNum);
            // 计算总价格
            userPositionDetail.setOrderTotalPrice(new BigDecimal(orderNum).multiply(userPosition.getSellOrderPrice()).setScale(6, BigDecimal.ROUND_HALF_UP));
        }

        userPositionDetail.setOrderDirection(userPosition.getOrderDirection());
        userPositionDetail.setOrderLever(userPosition.getOrderLever());
        userPositionDetail.setOrderFee(userPosition.getOrderFee());
        userPositionDetail.setOrderSpread(userPosition.getOrderSpread());
        userPositionDetail.setOrderStayFee(userPosition.getOrderStayFee());
        userPositionDetail.setOrderStayDays(userPosition.getOrderStayDays());
        userPositionDetail.setStopTargetPrice(userPosition.getStopTargetPrice());
        userPositionDetail.setProfitAndLose(userPosition.getProfitAndLose());
        userPositionDetail.setProfitTargetPrice(userPosition.getProfitTargetPrice());
        userPositionDetail.setAllProfitAndLose(userPosition.getAllProfitAndLose());
        userPositionDetail.setStockPlate(userPosition.getStockPlate());
        userPositionDetail.setMarginAdd(userPosition.getMarginAdd());
        userPositionDetail.setSpreadRatePrice(userPosition.getSpreadRatePrice());
        userPositionDetail.setInitPrice(userPosition.getInitPrice());
        userPositionDetail.setStockType(stockType);
        this.userPositionDetailMapper.insertSelective(userPositionDetail);
        return userPositionDetail.getId();
    }

    /**
     * 用户修改止盈止损
     */
    @Override
    public ServerResponse updateProfitTarget(String positionSn, Integer profitTarget, Integer
            stopTarget, HttpServletRequest request) {
        int update = 0;
        if (positionSn.contains("index")) {
            UserIndexPosition userIndexPosition = userIndexPositionMapper.selectIndexPositionBySn(positionSn.replace("index", ""));
            if (userIndexPosition == null) {
                return ServerResponse.createByErrorMsg("The index position does not exist.");
            }
            if (profitTarget != null && profitTarget > 0) {
                userIndexPosition.setProfitTargetPrice(BigDecimal.valueOf(profitTarget));
            }
            if (stopTarget != null && stopTarget > 0) {
                userIndexPosition.setStopTargetPrice(BigDecimal.valueOf(stopTarget));
            }
            log.info("指数止盈线" + profitTarget + "-------指数止损线" + stopTarget);
            update = this.userIndexPositionMapper.updateByPrimaryKeySelective(userIndexPosition);
        } else {
            UserPosition userPosition = this.userPositionMapper.findPositionBySn(positionSn);

            if (userPosition == null) {
                return ServerResponse.createByErrorMsg("The position record does not exist.");
            }
            if (profitTarget != null && profitTarget > 0) {
                userPosition.setProfitTargetPrice(BigDecimal.valueOf(profitTarget));
            }
            if (stopTarget != null && stopTarget > 0) {
                userPosition.setStopTargetPrice(BigDecimal.valueOf(stopTarget));
            }
            log.info("止盈线" + profitTarget + "-------止损线" + stopTarget);
            update = this.userPositionMapper.updateByPrimaryKeySelective(userPosition);
        }
        if (update > 0) {
            return ServerResponse.createBySuccessMsg("Successful modification");
        } else {
            return ServerResponse.createByErrorMsg("Modification Failed");
        }
    }

    /**
     * 挂单卖出逻辑
     * @param userId
     * @param sellNum
     * @return
     * @throws Exception
     */
    @Override
    public ServerResponse createSellout(Integer userId, String market, String stockId, Integer sellNum) throws Exception {
        User user = userMapper.selectById(userId);
        if (null == user) {
            return ServerResponse.createByErrorMsg("用户不存在，用户ID：" + userId);
        }

        String payPwd = user.getPayPwd();
        String decryptPassword = SymmetricCryptoUtil.decryptPassword(payPwd);
        return sellNew(stockId, market, sellNum, decryptPassword, userId);
    }

    /**
     * 卖出
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse sellNew(String code, String market, int sellNum,  String payPwd, Integer userId) throws Exception {

        // -------------- 幂等性调用（开始） --------------
//        if (!IdempotentUtils.judge(String.valueOf(userId), this.getClass())) {
//            return ServerResponse.createByErrorMsg("Failed to sell, do not resubmit.");
//        }

        String redisKey = "SELL_STOCK_" + userId + "_" + code;

        String ssasa = RedisShardedPoolUtils.get(redisKey);
        if (StringUtils.isNotBlank(ssasa)) {
            return ServerResponse.createByErrorMsg("出售失败，请勿重新提交.");
        }
        RedisShardedPoolUtils.setEx(redisKey, code, 1);


        if (userId == null) {
            return ServerResponse.createByErrorMsg("出售失败，用户信息不存在.");
        }
        // 判断卖出数量
        if (sellNum <= 0) {
            return ServerResponse.createByErrorMsg("售出数量必须大于0！");
        }

        User user = this.userMapper.selectByPrimaryKey(userId);
        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("卖出错误，网站设置表不存在");
            return ServerResponse.createByErrorMsg("卖出错误，网站设置表不存在.");
        }

        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        UserPosition userPosition = this.userPositionMapper.findUserPositionByCode(userId, code);

        if (null == userPosition) {
            log.error("卖出错误，股票不存在");
            return ServerResponse.createByErrorMsg("卖出错误，股票不存在.");
        }

        val orderNum = userPosition.getOrderNum();
        val sellouts = this.userPendingorderMapper.listSellOrderByStockIdAndUserId(userId, userPosition.getStockCode());
        val sum = sellouts.stream().mapToInt(UserPendingorder::getBuyNum).sum();
        if (orderNum.intValue() - sum < sellNum) {
            log.error("卖出错误，持仓股票数量不足");
            return ServerResponse.createByErrorMsg("卖出错误，持仓股票数量不足.");
        }
        // 判断是否在交易时间内
        boolean marketHours = BuyAndSellUtils.UsStockMarketHours(market, siteSetting);
        // 是否在盘前配置所设置的时间内
        int beforeFlag = 0;
        // 盘前配置对象
        StPremarketStock stPremarketStock = new StPremarketStock();
        if (!marketHours) {
            // 如果不在交易时间内，那么查询盘前交易配置
            List<StPremarketStock> list = stPremarketStockService.listByCodeAndMarket(code, market);
            if (CollectionUtils.isEmpty(list)) {
                log.info("卖出失败，不在交易时间内, market: " + market);
                return ServerResponse.createByErrorMsg("卖出失败，不在交易时间内.");
            }
            // 获取当前时间
            Date currentTime = new Date();
            DateTime time = new DateTime(currentTime);
            for (StPremarketStock stock : list) {
                // 盘前交易1--开始时间
                Date beforeStartTime = stock.getBeforeStartTime();
                DateTime aaBefore = new DateTime(beforeStartTime);
                // 盘前交易1--结束时间
                Date beforeEndTime = stock.getBeforeEndTime();
                DateTime bbBefore = new DateTime(beforeEndTime);
                if(time.after(aaBefore) && time.before(bbBefore)) {
                    beforeFlag = 1;
                    BeanUtils.copyProperties(stock, stPremarketStock);
                    break;
                }

                Date startTime = stock.getStartTime();
                DateTime aa = new DateTime(startTime);
                Date endTime = stock.getEndTime();
                DateTime bb = new DateTime(endTime);
                if(time.after(aa) && time.before(bb)){
                    beforeFlag = 2;
                    BeanUtils.copyProperties(stock, stPremarketStock);
                    break;
                }
            }
            if (beforeFlag == 0) {
                log.info("卖出失败，不再盘前交易配置所设置的时间段内, market: " + market);
                return ServerResponse.createByErrorMsg("卖出失败，不再盘前交易配置所设置的时间段内.");
            }
        }

        // 判断是否在后台设置中，如果在，则不允许购买
        if (isHoliday()) {
            return ServerResponse.createByErrorMsg("周末或节假日不能交易.");
        }

        /*实名认证开关开启*/
        if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
            return ServerResponse.createByErrorMsg("卖出失败，用户已被锁定.");
        }

        if (userPosition.getSellOrderId() != null) {
            return ServerResponse.createByErrorMsg("卖出失败，该订单已售出.");
        }

        if (1 == userPosition.getIsLock().intValue()) {
            return ServerResponse.createByErrorMsg("卖出失败 " + userPosition.getLockMsg());
        }

        if (!DateTimeUtil.isCanSell(userPosition.getBuyOrderTime(), siteSetting.getCantSellTimes().intValue())) {
            return ServerResponse.createByErrorMsg(siteSetting.getCantSellTimes() + "分钟内不可卖出");
        }


        // 校验支付密码
        String userPayPwd = user.getPayPwd();
        if (StringUtils.isBlank(userPayPwd)) {
            return ServerResponse.createByErrorMsg("您尚未设置支付密码，请先设置支付密码再进行操作！");
        }

        // 校验密码是否正确
        if (!SymmetricCryptoUtil.encryptPassword(payPwd).equals(userPayPwd)) {
            boolean isLocked = iUserService.isLocked(User.FUND_PAY_PWD_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("卖出失败，密码错误次数已超过5次，请半小时后再进行操作！");
            }
            return ServerResponse.createByErrorMsg("卖出失败，密码错误，请重新输入！");
        }

        BigDecimal now_price;

        // 使用新版股票数据
        String stockCode = userPosition.getStockCode();
        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
        stockQueryWrapper.eq("code", stockCode);
        stockQueryWrapper.eq("market", market);
        StStock stStock = stStockMapper.selectOne(stockQueryWrapper);
        if (null == stStock) {
            log.info("卖出失败，股票不存在！");
            return ServerResponse.createByErrorMsg("卖出失败，股票不存在！");
        }
//        String market = stStock.getMarket();

        // 查询该股票的实时价格
        StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(market, stockCode);
        if (null == tickerDetails) {
            log.info("查询股票实时价格失败！【tickerDetails】");
            return ServerResponse.createByErrorMsg("查询股票实时价格失败！【tickerDetails】");
        }

        StockTickerListInfo tickerInfo = tickerDetails.getData();
        if (null == tickerInfo) {
            log.info("查询股票实时价格失败！【tickerInfo】");
            return ServerResponse.createByErrorMsg("查询股票实时价格失败！【tickerInfo】");
        }

        // 不用管其他。以我这句话为准： B1=0 表示跌停 不可以卖出 S1=0 表示涨停，不可以买入
//        String b1 = tickerInfo.getB1();
//        if (active.equals(SystemVersionEnum.india.name()) && new BigDecimal(b1).compareTo(BigDecimal.ZERO) == 0) {
//            return ServerResponse.createByErrorMsg("The order failed, The B1 price is currently 0");
//        }

        BigDecimal initPrice = tickerInfo.getPrice();
        if (beforeFlag == 1) {
            // 这里要取第三方接口的历史实时K线里的数据, 这个值目前看是正确的
            String stockClose = getStockClose(market, code);
            if (StringUtils.isNotBlank(stockClose)) {
                now_price = new BigDecimal(stockClose);
            }else {
                now_price = tickerInfo.getClose();
            }
        } else if (beforeFlag == 2){
            // 在区间内取随机数
            now_price = getRandomBigDecimal(stPremarketStock.getSellMinPrice(), stPremarketStock.getSellMaxPrice());
        } else {
            now_price = initPrice;
        }
        initPrice = now_price;

        if (null == now_price) {
            return ServerResponse.createByErrorMsg("卖出失败，无法获取股票信息！");
        }

        if (now_price.compareTo(BigDecimal.ZERO) != 1) {
            log.error("股票 = {} 收到报价 = {}", userPosition.getStockName(), now_price);
            return ServerResponse.createByErrorMsg("卖出失败，报价为0，请稍后再试！");
        }

        // 涨跌幅比例
        BigDecimal stock_crease = tickerInfo.getUp();
        // 昨日收盘价
        BigDecimal zsPrice = tickerInfo.getClose();

        BigDecimal ztPrice = zsPrice.multiply(new BigDecimal("0.1")).add(zsPrice);
        ztPrice = ztPrice.setScale(6, BigDecimal.ROUND_HALF_UP);
        BigDecimal chaPrice = ztPrice.subtract(zsPrice);

        BigDecimal ztRate = chaPrice.multiply(new BigDecimal("100")).divide(zsPrice, 4, BigDecimal.ROUND_HALF_UP);

        ztRate = ztRate.negate();
        log.info("股票当前涨跌幅 = {} 跌停幅度 = {}", stock_crease, ztRate);
        if (stock_crease.compareTo(ztRate) == 0 && "Buy Up".equals(userPosition.getOrderDirection())) {
            return ServerResponse.createByErrorMsg("当前股票已触及跌停，无法进行卖出操作！");
        }

        //        计算买入总金额，即卖出数量乘以买入订单价格。
        BigDecimal all_buy_amt = new BigDecimal(sellNum).multiply(userPosition.getBuyOrderPrice()).setScale(6, BigDecimal.ROUND_HALF_UP);
        //        计算卖出总金额，即卖出数量乘以当前价格。
        BigDecimal all_sell_amt = now_price.multiply(new BigDecimal(sellNum));

        // 计算出盈亏金额  目前都是Buy Up
        BigDecimal profitLoss = all_sell_amt.subtract(all_buy_amt);

        userPosition.setSellOrderPrice(now_price);
        userPosition.setProfitAndLose(profitLoss);

        log.info("买入总金额 = {} , 卖出总金额 = {} , 盈亏 = {}", new Object[]{all_buy_amt, all_sell_amt, profitLoss});
        userPosition.setOrderSpread(BigDecimal.ZERO);
        userPosition.setOrderStayFee(BigDecimal.ZERO);
        userPosition.setSpreadRatePrice(BigDecimal.ZERO);

        // 卖出目前只收取卖出手续费
        BigDecimal sell_fee_amt = all_sell_amt.multiply(siteSetting.getSellFee()).setScale(6, BigDecimal.ROUND_HALF_UP);
        userPosition.setOrderFee(sell_fee_amt);

        //总手续费 = 卖出手续费 + 印花税 + 递延费 + 点差费  目前只要手续费了
        BigDecimal all_fee_amt = sell_fee_amt;
        // 修改持仓数据实体
        UserPosition updUserPosition = new UserPosition();
        updUserPosition.setId(userPosition.getId());
        // 如果剩余持股减去此次卖出仍大于0，那么不给sellOrderId赋值，只有全部卖出才会赋值
        if (userPosition.getOrderNum().intValue() == sellNum) {
            updUserPosition.setSellOrderId(GeneratePosition.getPositionId());
        }
        updUserPosition.setInitPrice(initPrice);
        updUserPosition.setSellOrderPrice(now_price);
        updUserPosition.setSellOrderTime(new Date());
        // 叠加手续费
        updUserPosition.setOrderFee(userPosition.getOrderFee().add(sell_fee_amt));
        // 扣除持股数量
        updUserPosition.setOrderNum(userPosition.getOrderNum().intValue() - sellNum);
        // 浮动盈亏
        updUserPosition.setProfitAndLose(userPosition.getProfitAndLose().add(profitLoss));
        // 总盈亏 这里是计算出的盈亏 减去 总手续费  初始值已经是总手续费(负值)
        BigDecimal all_profit = profitLoss.subtract(all_fee_amt);
        updUserPosition.setAllProfitAndLose(userPosition.getAllProfitAndLose().add(all_profit));
        // 印花税
        updUserPosition.setOrderSpread(BigDecimal.ZERO);
        // 点差费
        updUserPosition.setSpreadRatePrice(BigDecimal.ZERO);
        // 递延费
        updUserPosition.setOrderStayFee(BigDecimal.ZERO);
        int updatePositionCount = this.userPositionMapper.updateByPrimaryKeySelective(updUserPosition);

        // 卖出详情记录
        // 详情的总盈亏应该是本次的总盈亏 不能是主表的
        userPosition.setAllProfitAndLose(all_profit);
        userPosition.setInitPrice(initPrice);

        Integer detailId = insertPositionDetail(userPosition, sellNum, 2, 1);

        if (updatePositionCount > 0) {
            log.info("【用户id = {} 卖出】修改浮动盈亏记录成功", user.getId());
        } else {
            log.error("【用户 = {} 卖出】修改浮动盈亏记录出错",  user.getId());
            throw new Exception("【用户id = "+user.getId()+" 卖出】修改浮动盈亏记录成功");
        }

        // 退还账户资金时, 需要返还到配资账户中
        BigDecimal tradingAmount = user.getTradingAmount();
        BigDecimal enableAmt = user.getEnableAmt();
        log.info("用户id = {} 配资总资金 = {} , 可用资金 = {}",user.getId(), tradingAmount, enableAmt);

        // 当前需要退的钱 = （当前价格 * 卖出数量） - 手续费
        BigDecimal reckon_enable = all_sell_amt.subtract(all_fee_amt);
        log.info("用户卖出股票需要回款的金额  = {}", reckon_enable);

        // 开始退钱 默认如果使用了配资账户的钱  就先退配资账户  配资账户退完  退回到可用现金
        int updateUserCount = this.returnCorrespondAccount(user, reckon_enable);
        if (updateUserCount > 0) {
            log.info("【用户卖出】修改用户金额成功");
        } else {
            log.error("用户卖出】修改用户金额出错");
            throw new Exception("用户卖出】修改用户金额出错");
        }

        User userNew = this.userMapper.selectByPrimaryKey(userId);

        // 存储资金记录
        UserCashDetail ucd = new UserCashDetail();
        ucd.setPositionId(userPosition.getId());
        ucd.setAgentId(user.getAgentId());
        ucd.setAgentName(user.getAgentName());
        ucd.setUserId(user.getId());
        ucd.setUserName(user.getRealName());
        ucd.setDeType("Sell stock");
        ucd.setDeAmt(reckon_enable);
        ucd.setDeSummary(user.getNickName() + " 卖出股票：" + userPosition.getStockCode() + "/" + userPosition.getStockName()
                + "，买入总金额：" + all_buy_amt
                + "，卖出总金额：" + all_sell_amt
                + "，总手续费：" + all_fee_amt
                + "，盈亏金额：" + profitLoss
                + "，总盈亏：" + all_profit
                + "，回款金额：" + reckon_enable
                + "，可用余额：" + userNew.getEnableAmt()
                + "，配资金额：" + userNew.getTradingAmount());
        ucd.setAddTime(new Date());
        ucd.setIsRead(Integer.valueOf(0));
        int insertSxfCount = this.userCashDetailMapper.insert(ucd);
        if (insertSxfCount > 0) {
            log.info("【用户卖出】保存明细记录成功");
        } else {
            log.error("用户卖出】保存明细记录出错");
            throw new Exception("用户卖出】保存明细记录出错");
        }

        // 发送邮件提醒
        if (null != detailId) {
            if(SystemVersionEnum.global.name().equals(active)) {
                UserPositionDetail positionDetail = userPositionDetailMapper.selectById(detailId);
                sendHTMLMail.sendTradingBehaviorEmail(user, positionDetail);
            }
        }

        return ServerResponse.createBySuccessMsg("卖出股票成功！");
    }

    /**
     * 获取昨收价格
     * @param market
     * @param code
     * @return
     */
    private String getStockClose(String market, String code){
        StStockTickerKLineList kLineList = stocksComponent.queryKLineDetailsByMarketAndCode(market, code, "1day", "1");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "queryKLineDetails");

        if (null == kLineList) {
            return "";
        }

        String data = kLineList.getData();
        if (StringUtils.isBlank(data)) {
            return "";
        }

        String[] splitData = data.split(";");
        List<String> dataList = Arrays.asList(splitData);
        // 处理具体的字段  1时间戳,1昨日收,1今日开,1最高,1最低,1交易额,1交易量;  1723766400,1.44,1.57,1.57,1.38,2200787.922,1509194.0

        if(null != dataList && dataList.size() > 0){
            String dataStr = dataList.get(0);
            String[] splitDataStr = dataStr.split(",");
            List<String> asList = Arrays.asList(splitDataStr);

            if (asList.size() == 7) {
                return asList.get(1);
            }

        }
        return "";
    }

    public BigDecimal getRandomBigDecimal(BigDecimal min, BigDecimal max) {
        BigDecimal randomValue = new BigDecimal(new Random().nextDouble() * (max.doubleValue() - min.doubleValue()) + min.doubleValue());
        return randomValue.setScale(min.scale(), RoundingMode.HALF_UP);
    }

    // 卖出股票的钱退回对应账户的逻辑
    public int returnCorrespondAccount(User user, BigDecimal reckonEnable){
        // 查询用户配资记录 总的配资金额
        Integer userId = user.getId();
        Integer amount = fundsApplyMapper.getUserTotalAmountOfFunds(userId);
        if (null == amount) {
            // 配资账户未激活 直接退还到可用资金
            BigDecimal enableAmt = user.getEnableAmt();
            enableAmt = enableAmt.add(reckonEnable);

            User updateUser = new User();
            updateUser.setId(userId);
            updateUser.setEnableAmt(enableAmt);
            return userMapper.updateByPrimaryKeySelective(updateUser);
        }

        // 用户总的配资金额
        BigDecimal fundsAmount = new BigDecimal(amount);
        // 用户目前持有的配资金额  不包含保证金
        BigDecimal tradingAmount = user.getTradingAmount();
        BigDecimal enableAmt = user.getEnableAmt();

        // 需要退还到配资账户的钱
        BigDecimal fundsReturn = fundsAmount.subtract(tradingAmount);
        // 如果卖出股票的钱大于已使用的配资的钱，就先退还配资的钱，然后将剩余的退还到可用资金
        if (reckonEnable.compareTo(fundsReturn) > 0) {
            tradingAmount = tradingAmount.add(fundsReturn);

            // 卖出的钱如果有剩余需要退还到可用金额
            BigDecimal available = reckonEnable.subtract(fundsReturn);
            if (available.compareTo(BigDecimal.ZERO) > 0) {
                enableAmt = enableAmt.add(available);
            }
        }else {
            tradingAmount = tradingAmount.add(reckonEnable);
        }

        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setTradingAmount(tradingAmount);
        updateUser.setEnableAmt(enableAmt);
        return userMapper.updateByPrimaryKeySelective(updateUser);
    }


    public ServerResponse sell(String positionSn, int doType) throws Exception {
        log.info("【用户交易平仓】仓位编号={}，操作类型={}", positionSn, doType);

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("平仓出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("平仓出错，网站设置表不存在.");
        }
        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        UserPosition userPosition = this.userPositionMapper.findPositionBySn(positionSn);
        if (doType != 0) {
            String am_begin = siteSetting.getTransAmBegin();
            String am_end = siteSetting.getTransAmEnd();
            String pm_begin = siteSetting.getTransPmBegin();
            String pm_end = siteSetting.getTransPmEnd();
            boolean am_flag = BuyAndSellUtils.isTransTime(am_begin, am_end);
            boolean pm_flag = BuyAndSellUtils.isTransTime(pm_begin, pm_end);
            log.info("是否在上午交易时间 = {} 是否在下午交易时间 = {}", Boolean.valueOf(am_flag), Boolean.valueOf(pm_flag));
            if (!am_flag && !pm_flag) {
                return ServerResponse.createByErrorMsg("未能平仓，且不在交易期内.");
            }

            // 判断是否在后台设置中，如果在，则不允许购买
            if (isHoliday()) {
                return ServerResponse.createByErrorMsg("不能在周末或节假日交易.");
            }

        }


        if (userPosition == null) {
            return ServerResponse.createByErrorMsg("关闭失败，订单不存在.");
        }

        User user = this.userMapper.selectByPrimaryKey(userPosition.getUserId());
        if (user == null) {
            return ServerResponse.createByErrorMsg("平仓失败，用户不存在");
        }

        /*实名认证开关开启*/
        if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
            return ServerResponse.createByErrorMsg("该用户已被锁定，平仓失败");
        }


        if (userPosition.getSellOrderId() != null) {
            return ServerResponse.createByErrorMsg("平仓失败，该订单已完成平仓");
        }

        if (1 == userPosition.getIsLock().intValue()) {
            return ServerResponse.createByErrorMsg("平仓失败，" + userPosition.getLockMsg());
        }

        if (!DateTimeUtil.isCanSell(userPosition.getBuyOrderTime(), siteSetting.getCantSellTimes().intValue())) {
            return ServerResponse.createByErrorMsg(String.format("持仓后%d分钟内不可平仓", siteSetting.getCantSellTimes()));
        }

//        if (DateTimeUtil.sameDate(DateTimeUtil.getCurrentDate(),userPosition.getBuyOrderTime())) {
//            return ServerResponse.createByErrorMsg("当天入仓的股票需要隔天才能出仓");
//        }
        BigDecimal now_price;
        //股票卖出的 价格 数据源
        // 使用新版股票数据
        String stockCode = userPosition.getStockCode();
        String market = userPosition.getStockSpell();
        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
        stockQueryWrapper.eq("code", stockCode);
        stockQueryWrapper.eq("market", market);
        StStock stStock = stStockMapper.selectOne(stockQueryWrapper);
        if (null == stStock) {
            log.info("下单失败，股票不存在！");
        }

        // 查询该股票的实时价格
        StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(stStock.getMarket(), stockCode);
        if (null == tickerDetails) {
            log.info("查询股票实时价格失败！【tickerDetails】");
        }

        StockTickerListInfo tickerInfo = tickerDetails.getData();
        if (null == tickerInfo) {
            log.info("查询股票实时价格失败！【tickerInfo】");
        }

        // 判断S1 B1 如果都是0 不能平仓
        String b1 = tickerInfo.getB1();
        String s1 = tickerInfo.getS1();
        if (new BigDecimal(b1).compareTo(BigDecimal.ZERO) == 0 && new BigDecimal(s1).compareTo(BigDecimal.ZERO) == 0) {
            return ServerResponse.createByErrorMsg("平仓失败，当前买一价和卖一价均为0");
        }

        now_price = tickerInfo.getPrice();
        if (null == now_price) {
            return ServerResponse.createByErrorMsg("平仓失败，无法获取股票信息");
        }


        if (now_price.compareTo(new BigDecimal("0")) != 1) {
            log.error("股票 = {} 收到报价 = {}", userPosition.getStockName(), now_price);
            return ServerResponse.createByErrorMsg("收到无效报价(0)，平仓失败，请稍后重试");
        }

        // 涨跌幅比例
        BigDecimal stock_crease = tickerInfo.getUp();
        // 昨日收盘价
        BigDecimal zsPrice = tickerInfo.getClose();

        BigDecimal ztPrice = zsPrice.multiply(new BigDecimal("0.1")).add(zsPrice);
        ztPrice = ztPrice.setScale(6, BigDecimal.ROUND_HALF_UP);
        BigDecimal chaPrice = ztPrice.subtract(zsPrice);

        BigDecimal ztRate = chaPrice.multiply(new BigDecimal("100")).divide(zsPrice, 2, 4);

        ztRate = ztRate.negate();
        log.info("股票当前涨跌幅 = {} 跌停幅度 = {}", stock_crease, ztRate);
        if (stock_crease.compareTo(ztRate) == 0 && "买涨".equals(userPosition.getOrderDirection())) {
            return ServerResponse.createByErrorMsg("当前股票已触发跌停限制，无法卖出");
        }

        Integer buy_num = userPosition.getOrderNum();

        BigDecimal all_buy_amt = userPosition.getOrderTotalPrice();
        BigDecimal all_sell_amt = now_price.multiply(new BigDecimal(buy_num.intValue()));

        BigDecimal profitLoss;
        if ("Buy Up".equals(userPosition.getOrderDirection())) {
            log.info("买卖方向：{}", "涨");

            profitLoss = all_sell_amt.subtract(all_buy_amt);
        } else {
            log.info("买卖方向：{}", "跌");
            profitLoss = all_buy_amt.subtract(all_sell_amt);
        }
        log.info("买入总金额 = {} , 卖出总金额 = {} , 盈亏 = {}", new Object[]{all_buy_amt, all_sell_amt, profitLoss});

        BigDecimal buy_fee_amt = userPosition.getOrderFee();
        log.info("买入手续费 = {}", buy_fee_amt);

        BigDecimal orderSpread = userPosition.getOrderSpread();
        log.info("印花税 = {}", orderSpread);

        BigDecimal orderStayFee = userPosition.getOrderStayFee();
        log.info("递延费 = {}", orderStayFee);

        BigDecimal spreadRatePrice = userPosition.getSpreadRatePrice();
        log.info("点差费 = {}", spreadRatePrice);

        BigDecimal sell_fee_amt = all_sell_amt.multiply(siteSetting.getSellFee()).setScale(6, BigDecimal.ROUND_HALF_UP);
        log.info("卖出手续费 = {}", sell_fee_amt);

        //总手续费= 买入手续费+卖出手续费+印花税+递延费+点差费
        BigDecimal all_fee_amt = buy_fee_amt.add(sell_fee_amt).add(orderSpread).add(orderStayFee).add(spreadRatePrice);
        log.info("总的手续费费用 = {}", all_fee_amt);

        userPosition.setSellOrderId(GeneratePosition.getPositionId());
        userPosition.setSellOrderPrice(now_price);
        userPosition.setSellOrderTime(new Date());

        BigDecimal order_fee_all = buy_fee_amt.add(sell_fee_amt);
        userPosition.setOrderFee(order_fee_all);

        userPosition.setProfitAndLose(profitLoss);

        BigDecimal all_profit = profitLoss.subtract(all_fee_amt);
        userPosition.setAllProfitAndLose(all_profit);

        int updatePositionCount = this.userPositionMapper.updateByPrimaryKeySelective(userPosition);

        UserPosition position = this.userPositionMapper.findUserPositionByCode(user.getId(), stockCode);
        // 卖出详情记录
        insertPositionDetail(userPosition, position.getOrderNum(), 2, 1);

        if (updatePositionCount > 0) {
            log.info("【用户平仓】修改浮动盈亏记录成功");
        } else {
            log.error("用户平仓】修改浮动盈亏记录出错");
            throw new Exception("用户平仓操作] 更新浮动盈亏记录异常");
        }

        //修改用户可用余额 = 当前可用余额 + 总盈亏 + 买入总金额 + 追加保证金
        BigDecimal user_all_amt = user.getUserIndexAmt();
        BigDecimal user_enable_amt = user.getEnableIndexAmt();

        log.info("用户原本总资金 = {} , 可用 = {}", user_all_amt, user_enable_amt);

        BigDecimal freez_amt = all_buy_amt.divide(new BigDecimal(userPosition.getOrderLever().intValue()), 2, 4);
        BigDecimal reckon_all = user_all_amt.add(all_profit);

        BigDecimal reckon_enable = user_enable_amt.add(all_profit).add(freez_amt).add(userPosition.getMarginAdd());

        log.info("用户平仓后的总资金  = {} , 可用资金 = {}", reckon_all, reckon_enable);

        user.setUserIndexAmt(reckon_all);
        user.setEnableIndexAmt(reckon_enable);

        int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);
        if (updateUserCount > 0) {
            log.info("【用户平仓】修改用户金额成功");
        } else {
            log.error("用户平仓】修改用户金额出错");
            throw new Exception("用户平仓操作] 更新用户资金异常");
        }

        UserCashDetail ucd = new UserCashDetail();
        ucd.setPositionId(userPosition.getId());
        ucd.setAgentId(user.getAgentId());
        ucd.setAgentName(user.getAgentName());
        ucd.setUserId(user.getId());
        ucd.setUserName(user.getRealName());
        ucd.setDeType("Close out a position");
        ucd.setDeAmt(all_profit);
        ucd.setDeSummary("股票平仓操作：" + userPosition.getStockCode() + "/" + userPosition.getStockName()
                + "，冻结资金：" + freez_amt
                + "，总手续费：" + all_fee_amt
                + "，递延费：" + orderStayFee
                + "，印花税：" + orderSpread
                + "，浮动盈亏：" + profitLoss
                + "，净盈亏：" + all_profit);
        ucd.setAddTime(new Date());
        ucd.setIsRead(Integer.valueOf(0));

        int insertSxfCount = this.userCashDetailMapper.insert(ucd);
        if (insertSxfCount > 0) {
            //核算代理收入-平仓手续费
//            iAgentAgencyFeeService.AgencyFeeIncome(2, userPosition.getPositionSn());
            //核算代理收入-分红
//            iAgentAgencyFeeService.AgencyFeeIncome(4, userPosition.getPositionSn());
            log.info("【用户平仓】保存明细记录成功");
        } else {
            log.error("用户平仓】保存明细记录出错");
            throw new Exception("用户平仓操作] 保存交易明细记录异常");
        }
        return ServerResponse.createBySuccessMsg("仓位平仓成功");
    }

    //用户追加保证金操作
    public ServerResponse addmargin(String positionSn, int doType, BigDecimal marginAdd) throws Exception {
        log.info("【用户追加保证金】 positionSn = {} ， dotype = {}", positionSn, Integer.valueOf(doType));

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("追加保证金出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("追加保证金出错，网站设置表不存在");
        }

        if (doType != 0) {
            /*String am_begin = siteSetting.getTransAmBegin();
            String am_end = siteSetting.getTransAmEnd();
            String pm_begin = siteSetting.getTransPmBegin();
            String pm_end = siteSetting.getTransPmEnd();
            boolean am_flag = BuyAndSellUtils.isTransTime(am_begin, am_end);
            boolean pm_flag = BuyAndSellUtils.isTransTime(pm_begin, pm_end);
            log.info("是否在上午交易时间 = {} 是否在下午交易时间 = {}", Boolean.valueOf(am_flag), Boolean.valueOf(pm_flag));
            if (!am_flag && !pm_flag) {
                return ServerResponse.createByErrorMsg("追加失败，不在交易时段内");
            }*/
        }

        UserPosition userPosition = this.userPositionMapper.findPositionBySn(positionSn);
        if (userPosition == null) {
            return ServerResponse.createByErrorMsg("追加保证金失败，仓位不存在");
        }

        User user = this.userMapper.selectByPrimaryKey(userPosition.getUserId());
        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        if (!siteProduct.getStockMarginDisplay()) {
            return ServerResponse.createByErrorMsg("系统禁止追加操作，请联系管理员");
        }

        // 判断是否在后台设置中，如果在，则不允许购买
        if (isHoliday()) {
            return ServerResponse.createByErrorMsg("非交易日无法操作（周末及节假日）");
        }

        if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
            return ServerResponse.createByErrorMsg("追加失败，用户账户已被锁定");
        }

        if (1 == userPosition.getIsLock().intValue()) {
            return ServerResponse.createByErrorMsg("追加失败，" + userPosition.getLockMsg());
        }

        BigDecimal user_all_amt = user.getUserAmt();
        BigDecimal user_enable_amt = user.getEnableAmt();
        int compareUserAmtInt = user_enable_amt.compareTo(marginAdd);
        log.info("用户可用金额 = {}  追加金额 =  {}", user_enable_amt, marginAdd);
        log.info("比较 用户金额 和 实际 购买金额 =  {}", Integer.valueOf(compareUserAmtInt));
        if (compareUserAmtInt == -1) {
            return ServerResponse.createByErrorMsg("追加失败，融资金额不足 " + marginAdd + " 元");
        }


        userPosition.setMarginAdd(userPosition.getMarginAdd().add(marginAdd));

        int updatePositionCount = this.userPositionMapper.updateByPrimaryKeySelective(userPosition);
        if (updatePositionCount > 0) {
            log.info("【用户追加保证金】追加保证金成功");
        } else {
            log.error("用户追加保证金】追加保证金出错");
            throw new Exception("用户追加保证金] 保证金增加操作异常");
        }

        //修改用户可用余额=当前可用余额-追加金额
        BigDecimal reckon_enable = user_enable_amt.subtract(marginAdd);

        log.info("用户追加保证金后的总资金  = {} , 可用资金 = {}", user_all_amt, reckon_enable);
        user.setEnableAmt(reckon_enable);
        int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);
        if (updateUserCount > 0) {
            log.info("【用户平仓】修改用户金额成功");
        } else {
            log.error("用户平仓】修改用户金额出错");
            throw new Exception("用户平仓操作] 更新用户资金异常");
        }

        UserCashDetail ucd = new UserCashDetail();
        ucd.setPositionId(userPosition.getId());
        ucd.setAgentId(user.getAgentId());
        ucd.setAgentName(user.getAgentName());
        ucd.setUserId(user.getId());
        ucd.setUserName(user.getRealName());
        ucd.setDeType("Additional margin");
        ucd.setDeAmt(marginAdd.multiply(new BigDecimal("-1")));
        ucd.setDeSummary("Additional Stocks，" + userPosition.getStockCode() + "/" + userPosition.getStockName() + ",marginAdd：" + marginAdd);

        ucd.setAddTime(new Date());
        ucd.setIsRead(Integer.valueOf(0));

        int insertSxfCount = this.userCashDetailMapper.insert(ucd);
        if (insertSxfCount > 0) {
            log.info("【用户平仓】保存明细记录成功");
        } else {
            log.error("用户平仓】保存明细记录出错");
            throw new Exception("用户平仓操作] 保存交易明细记录异常");
        }
        return ServerResponse.createBySuccessMsg("保证金追加成功");
    }


    public ServerResponse lock(Integer positionId, Integer state, String lockMsg) {
        if (positionId == null || state == null) {
            return ServerResponse.createByErrorMsg("参数不能为空");
        }

        UserPosition position = this.userPositionMapper.selectByPrimaryKey(positionId);
        if (position == null) {
            return ServerResponse.createByErrorMsg("仓位不存在");
        }

        if (position.getSellOrderId() != null) {
            return ServerResponse.createByErrorMsg("平仓单禁止锁定操作");
        }

        if (state.intValue() == 1 &&
                StringUtils.isBlank(lockMsg)) {
            return ServerResponse.createByErrorMsg("请填写仓位锁定提示信息");
        }

        if (state.intValue() == 1) {
            position.setIsLock(Integer.valueOf(1));
            position.setLockMsg(lockMsg);
        } else {
            position.setIsLock(Integer.valueOf(0));
        }

        int updateCount = this.userPositionMapper.updateByPrimaryKeySelective(position);
        if (updateCount > 0) {
            return ServerResponse.createBySuccessMsg("操作成功");
        }
        return ServerResponse.createByErrorMsg("操作失败");
    }

    public ServerResponse del(Integer positionId) {
        if (positionId == null) {
            return ServerResponse.createByErrorMsg("Id cannot be empty");
        }
        UserPosition position = this.userPositionMapper.selectByPrimaryKey(positionId);
        if (position == null) {
            ServerResponse.createByErrorMsg("The position does not exist.");
        }
        /*if (position.getSellOrderId() == null) {
            return ServerResponse.createByErrorMsg("持仓单不能删除！");
        }*/
        int updateCount = this.userPositionMapper.deleteByPrimaryKey(positionId);
        if (updateCount > 0) {
            return ServerResponse.createBySuccessMsg("Deleted successfully");
        }
        return ServerResponse.createByErrorMsg("Delete Failed");
    }

    public ServerResponse findMyPositionByCodeAndSpell(String stockCode, String stockSpell, Integer state, HttpServletRequest request, int pageNum, int pageSize) {
        User user = this.iUserService.getCurrentRefreshUser(request);

        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        List<UserPosition> userPositions = this.userPositionMapper.findMyPositionByCodeAndSpell(user.getId(), stockCode, stockSpell, state);

        List<UserPositionVO> userPositionVOS = Lists.newArrayList();
        BigDecimal allProfitAndLose = BigDecimal.ZERO;
        if (userPositions.size() > 0) {
            for (UserPosition position : userPositions) {
                // 这里调
                UserPositionVO userPositionVO = assembleUserPositionVO(position);
                userPositionVOS.add(userPositionVO);
                // 总盈亏
                allProfitAndLose = allProfitAndLose.add(userPositionVO.getAllProfitAndLose());
            }
        }

        PageInfo pageInfo = new PageInfo(page);
        StockPageInfo stockPageInfo = new StockPageInfo(userPositionVOS);
        BeanUtils.copyProperties(pageInfo, stockPageInfo);
        stockPageInfo.setAllProfitAndLose(allProfitAndLose.setScale(6, BigDecimal.ROUND_HALF_UP));
        stockPageInfo.setList(userPositionVOS);
        return ServerResponse.createBySuccess(stockPageInfo);
    }

    /**
     * 计算所有冻结资产和盈亏情况
     * @param userId
     * @return
     */
    public PositionVO findUserPositionAllProfitAndLose(Integer userId) {
        // 获取用户信息
        User user = userMapper.selectByPrimaryKey(userId);
        // 总盈亏 股票盈亏  + 基金盈亏
        BigDecimal allProfitAndLose = new BigDecimal(BigInteger.ZERO);
        // 冻结资产  冻结资金：挂单冻结  + 新股收购 + 融资保证金
        BigDecimal allFreezeAssets = new BigDecimal(BigInteger.ZERO);
        // 计算总市值 股票市值 + 基金市值
        BigDecimal totalMarket = new BigDecimal(BigInteger.ZERO);
        // 总资金 = 用户现金+配资资金+冻结资金+总市值
        BigDecimal totalFunds = new BigDecimal(BigInteger.ZERO);
        // 可用资金 = 配资资金+用户现金
        BigDecimal availableFunds = new BigDecimal(BigInteger.ZERO);


        if (null != user) {
            // 总资金 - 加上配资资金(借的钱)
            BigDecimal fundsAmount = user.getTradingAmount();
            BigDecimal enableAmt = user.getEnableAmt();
            // 总资金 - 加上用户可用现金
            totalFunds = totalFunds.add(enableAmt).add(fundsAmount);

            // 可用资金 - 加上用户现金         // 可用资金 - 加上配资资金(借的钱)
            availableFunds = availableFunds.add(enableAmt).add(fundsAmount);

        }





        // 计算股票的盈亏 查询所有没有卖出的股票数据
        List<UserPosition> userPositions = this.userPositionMapper.findPositionByUserIdAndSellIdIsNull(userId);
        for (UserPosition position : userPositions) {
            // 交易所
            String stockSpell = position.getStockSpell();
            // 股票代码
            String stockCode = position.getStockCode();
            // 实时查询最新价格
            StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(stockSpell, stockCode);
            BigDecimal nowPrice = new BigDecimal("0.00");
            if (null != tickerDetails) {
                StockTickerListInfo data = tickerDetails.getData();
                if(null != data) {
                    nowPrice = data.getPrice();
                }
            }

            // 计算当前持有的股票的总市值
            Integer orderNum = position.getOrderNum();
            // 印度股票需要转成美金
            BigDecimal stockMarket = nowPrice.multiply(new BigDecimal(orderNum));
            totalMarket = totalMarket.add(stockMarket);

            if (nowPrice.compareTo(BigDecimal.ZERO) != 0) {
                // 购买时的价格  应该取initPrice
                BigDecimal buyPrice = position.getInitPrice();
                // 计算差值
                BigDecimal subPrice = nowPrice.subtract(buyPrice);
                // 浮动盈亏
                BigDecimal profit_and_lose = subPrice.multiply(new BigDecimal(position.getOrderNum().intValue()));

                // 计算所有相关费用的总和，包括订单费用、交易费差和停留费等，并将结果存储在 total_fee 变量中。
                BigDecimal total_fee = position.getOrderFee().add(position.getOrderSpread()).add(position.getOrderStayFee()).add(position.getSpreadRatePrice());

                // 计算扣除了总费用后的实际盈亏，并将结果存储在 position_profit 变量中。
                BigDecimal position_profit = profit_and_lose.subtract(total_fee);
                // 将当前持仓的盈亏累加到 allProfitAndLose 变量中，用于跟踪所有持仓的总盈亏  这里类似浮动盈亏
//                BigDecimal currentAllProfitAndLose = position.getAllProfitAndLose();
                // 因为购买的时候已经扣除各种费用了，allProfitAndLose初始会是一个负值，所以当每次查询计算的时候 只需要在此基础上加上当前的浮动盈亏就可以了
                allProfitAndLose = allProfitAndLose.add(position_profit);


                // 订单的冻结资金
                // 计算订单总价 position.getOrderTotalPrice() 除以订单杠杆 position.getOrderLever() 的整数值，并保留两位小数
//                BigDecimal position_freez = position.getOrderTotalPrice().divide(new BigDecimal(position.getOrderLever().intValue()), 2, 4);
                //BigDecimal position_freez = position.getOrderTotalPrice();
                // 计算总冻结资金
//                allFreezeAssets = allFreezeAssets.add(position_freez).add(position.getMarginAdd());
                continue;
            }
            log.info("查询所有持仓单的总盈亏，现价返回0，当前为集合竞价");
        }

        // 计算持有基金的总盈亏
        BigDecimal totalFundProfit = new BigDecimal(BigInteger.ZERO);
        List<FundPositionRecordVo> recordVoList = stFundApplyMapper.fundPositionRecord(userId);
        for (FundPositionRecordVo recordVo : recordVoList) {

            // 盈亏应该是当前基金的净值 减去 购买时的净值 乘以当前持有的份额
            BigDecimal currentPrice = recordVo.getCurrentPrice();
            BigDecimal initPrice = recordVo.getInitPrice();

            BigDecimal purchaseShare = recordVo.getPurchaseShare();
            BigDecimal profit = currentPrice.subtract(initPrice).multiply(purchaseShare);
            // 盈亏
            totalFundProfit = totalFundProfit.add(profit);

            // 持有金额应该时当前净值 乘以 持有份额
            BigDecimal holdPrice = currentPrice.multiply(purchaseShare).setScale(4, BigDecimal.ROUND_HALF_UP);
            // 持有金额
            totalMarket = totalMarket.add(holdPrice);
        }
        allProfitAndLose = allProfitAndLose.add(totalFundProfit);

        // 冻结 - 加上配资保证金
        List<FundsApply> fundsApplyList = fundsApplyMapper.getUserEnabledSubaccount(userId);
        for (FundsApply fundsApply : fundsApplyList) {
            // 保证金
            allFreezeAssets = allFreezeAssets.add(fundsApply.getMargin());
        }

        // 冻结 - 挂单冻结
//        QueryWrapper<UserPendingorder> pendingorderQueryWrapper = new QueryWrapper<>();
//        pendingorderQueryWrapper.eq("user_id", userId);
//        pendingorderQueryWrapper.eq("status", 0);
//        List<UserPendingorder> userPendingorders = userPendingorderMapper.selectList(pendingorderQueryWrapper);
//        for (UserPendingorder pendingorder : userPendingorders) {
//            Integer buyNum = pendingorder.getBuyNum();
//            BigDecimal nowPrice = pendingorder.getNowPrice();
//
//            BigDecimal freezeAssets = new BigDecimal(buyNum).multiply(nowPrice);
//
//            allFreezeAssets = allFreezeAssets.add(freezeAssets);
//        }

        if (null != user) {
            //  冻结 - 申购新股 和 挂单 - 这里取用户表的 djzj字段  目前新股和挂单都存在了djzj字段
            BigDecimal djzj = user.getDjzj();
            allFreezeAssets = allFreezeAssets.add(djzj);
        }

//        QueryWrapper<UserStockSubscribe> subscribeQueryWrapper = new QueryWrapper<>();
//        subscribeQueryWrapper.eq("user_id", userId);
//        // 2 未中签 5 是转持仓 不转持仓之前都是冻结状态
//        subscribeQueryWrapper.ne("status", 5).or().ne("status", 2);
//        List<UserStockSubscribe> userStockSubscribes = userStockSubscribeMapper.selectList(subscribeQueryWrapper);
//        for (UserStockSubscribe stockSubscribe : userStockSubscribes) {
//            // 总金额
//            BigDecimal bond = stockSubscribe.getBond();
//            allFreezeAssets = allFreezeAssets.add(bond);
//        }

        // 总资金 - 加上冻结资金
        totalFunds = totalFunds.add(allFreezeAssets);

        // 总资金 = 加上总市值
        totalFunds = totalFunds.add(totalMarket);

        PositionVO positionVO = new PositionVO();
        // 股票的浮动盈亏加上基金的总盈亏
        positionVO.setAllProfitAndLose(allProfitAndLose.setScale(6, BigDecimal.ROUND_HALF_UP));
        // 冻结资金
        positionVO.setAllFreezAmt(allFreezeAssets.setScale(6, BigDecimal.ROUND_HALF_UP));
        positionVO.setTotalFunds(totalFunds.setScale(6, BigDecimal.ROUND_HALF_UP));
        positionVO.setAvailableFunds(availableFunds.setScale(6, BigDecimal.ROUND_HALF_UP));
        positionVO.setTotalMarket(totalMarket.setScale(6, BigDecimal.ROUND_HALF_UP));
        return positionVO;
    }

    public List<UserPosition> findPositionByUserIdAndSellIdIsNull(Integer userId) {
        return this.userPositionMapper.findPositionByUserIdAndSellIdIsNull(userId);
    }

    public List<UserPosition> findPositionByStockCodeAndTimes(int minuteTimes, String stockCode, Integer userId) {
        Date paramTimes = null;
        paramTimes = DateTimeUtil.parseToDateByMinute(minuteTimes);

        return this.userPositionMapper.findPositionByStockCodeAndTimes(paramTimes, stockCode, userId);
    }

    public Integer findPositionNumByTimes(int minuteTimes, Integer userId) {
        Date beginDate = DateTimeUtil.parseToDateByMinute(minuteTimes);
        Integer transNum = this.userPositionMapper.findPositionNumByTimes(beginDate, userId);
        log.info("用户 {} 在 {} 分钟之内 交易手数 {}", new Object[]{userId, Integer.valueOf(minuteTimes), transNum});
        return transNum;
    }

    public ServerResponse listByAgent(String stockCode, Integer positionType, Integer state, Integer userId, Integer agentId,
                                      String positionSn, String userPhone, String beginTime, String endTime,
                                      HttpServletRequest request, int pageNum, int pageSize) {
        AgentUser currentAgent = this.iAgentUserService.getCurrentAgent(request);


        if (agentId != null) {
            AgentUser agentUser = this.agentUserMapper.selectByPrimaryKey(agentId);
            if (agentUser != null && !agentUser.getParentId().equals(currentAgent.getId())) {
                return ServerResponse.createByErrorMsg("You can't query the positions of non-lower-level agent users.");
            }
        }

        Integer searchId = null;
        if (agentId == null) {
            searchId = currentAgent.getId();
        } else {
            searchId = agentId;
        }


        Timestamp begin_time = null;
        if (StringUtils.isNotBlank(beginTime)) {
            begin_time = DateTimeUtil.searchStrToTimestamp(beginTime);
        }
        Timestamp end_time = null;
        if (StringUtils.isNotBlank(endTime)) {
            end_time = DateTimeUtil.searchStrToTimestamp(endTime);
        }

        PageHelper.startPage(pageNum, pageSize);


        List<UserPosition> userPositions = this.userPositionMapper.listByAgent(stockCode, positionType, state, userId,
                searchId, positionSn, userPhone, begin_time, end_time);

        List<AgentPositionVO> agentPositionVOS = Lists.newArrayList();
        for (UserPosition position : userPositions) {
            AgentPositionVO agentPositionVO = assembleAgentPositionVO(position);
            agentPositionVOS.add(agentPositionVO);
        }

        PageInfo pageInfo = new PageInfo(userPositions);
        pageInfo.setList(agentPositionVOS);

        return ServerResponse.createBySuccess(pageInfo);
    }

    public ServerResponse getIncome(String stockCode, Integer agentId, Integer positionType, String userPhone, String beginTime, String endTime) {
        if (StringUtils.isBlank(beginTime) || StringUtils.isBlank(endTime)) {
            return ServerResponse.createByErrorMsg("Time cannot be empty.");
        }

        Timestamp begin_time = null;
        if (StringUtils.isNotBlank(beginTime)) {
            begin_time = DateTimeUtil.searchStrToTimestamp(beginTime);
        }
        Timestamp end_time = null;
        if (StringUtils.isNotBlank(endTime)) {
            end_time = DateTimeUtil.searchStrToTimestamp(endTime);
        }


        List<UserPosition> userPositions = this.userPositionMapper.listByAgent(stockCode, positionType, Integer.valueOf(1),
                null, agentId, null,userPhone, begin_time, end_time);


        BigDecimal order_fee_amt = new BigDecimal("0");
        BigDecimal order_profit_and_lose = new BigDecimal("0");
        BigDecimal order_profit_and_lose_all = new BigDecimal("0");

        for (UserPosition position : userPositions) {

            order_fee_amt = order_fee_amt.add(position.getOrderFee()).add(position.getOrderSpread()).add(position.getOrderStayFee());

            order_profit_and_lose = order_profit_and_lose.add(position.getProfitAndLose());

            order_profit_and_lose_all = order_profit_and_lose_all.add(position.getAllProfitAndLose());
        }

        AgentIncomeVO agentIncomeVO = new AgentIncomeVO();
        agentIncomeVO.setOrderSize(Integer.valueOf(userPositions.size()));
        agentIncomeVO.setOrderFeeAmt(order_fee_amt);
        agentIncomeVO.setOrderProfitAndLose(order_profit_and_lose);
        agentIncomeVO.setOrderAllAmt(order_profit_and_lose_all);

        return ServerResponse.createBySuccess(agentIncomeVO);
    }
    @Override
    public ServerResponse listByAdmin(Integer agentId, Integer positionType, Integer state, Integer userId, String stockCode, String positionSn,
                                      String userPhone, String beginTime, String endTime, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);


        Timestamp begin_time = null;
        if (StringUtils.isNotBlank(beginTime)) {
            begin_time = DateTimeUtil.searchStrToTimestamp(beginTime);
        }
        Timestamp end_time = null;
        if (StringUtils.isNotBlank(endTime)) {
            end_time = DateTimeUtil.searchStrToTimestamp(endTime);
        }


        List<UserPosition> userPositions = this.userPositionMapper.listByAgent(stockCode, positionType, state, userId, agentId,
                positionSn, userPhone, begin_time, end_time);

        List<AdminPositionVO> adminPositionVOS = Lists.newArrayList();
        for (UserPosition position : userPositions) {
            AdminPositionVO adminPositionVO = assembleAdminPositionVO(position);
            adminPositionVOS.add(adminPositionVO);
        }

        PageInfo pageInfo = new PageInfo(userPositions);
        pageInfo.setList(adminPositionVOS);

        return ServerResponse.createBySuccess(pageInfo);
    }

    public int CountPositionNum(Integer state, Integer accountType) {
        return this.userPositionMapper.CountPositionNum(state, accountType);
    }

    public BigDecimal CountPositionProfitAndLose() {
        return this.userPositionMapper.CountPositionProfitAndLose();
    }

    public BigDecimal CountPositionAllProfitAndLose() {
        return this.userPositionMapper.CountPositionAllProfitAndLose();
    }

    @Transactional
    public ServerResponse create(Integer userId, String stockCode,String market, String buyPrice, String buyTime,
                                 Integer buyNum, Integer buyType, Integer lever, BigDecimal targetPrice, BigDecimal stopTarget) {

        if (userId == null || StringUtils.isBlank(buyPrice) || StringUtils.isBlank(stockCode) ||
                StringUtils.isBlank(buyTime) || buyNum == null || buyType == null || lever == null) {
            log.info("参数为空");
            return ServerResponse.createByErrorMsg("Parameters cannot be empty.");

        }

        User user = this.userMapper.selectByPrimaryKey(userId);
        if (user == null) {
            log.info("用户不存在");
            return ServerResponse.createByErrorMsg("User does not exist");

        }

        String payPwd = user.getPayPwd();
        String decryptPassword = SymmetricCryptoUtil.decryptPassword(payPwd);
        return actualPurchase(user, stockCode, market, buyNum, buyType, lever, targetPrice, stopTarget, StockBuyTypeEnum.PENDING_BUY.getType(), decryptPassword);


//        if (user.getAccountType().intValue() != 1) {
//            return ServerResponse.createByErrorMsg("正式用户不能生成持仓单");
//        }
//        SiteProduct siteProduct = iSiteProductService.getProductSetting();
//        if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
//            log.info("下单失败，账户已被锁定");
//            return ServerResponse.createByErrorMsg("The order failed and the account has been locked.");
//
//        }
//
//        // 查询股票新接口数据
//        // 使用新版股票数据
//        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
//        stockQueryWrapper.eq("code", stockCode);
//        StStock stStock = stStockMapper.selectOne(stockQueryWrapper);
//        if (null == stStock) {
//            log.info("下单失败，股票不存在！");
//        }
//        String market = stStock.getMarket();
//
//
//        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
//        if (siteSetting == null) {
//            log.error("下单出错，网站设置表不存在");
//            return ServerResponse.createByErrorMsg("The order failed, and the system settings are wrong.");
//        }
//
//
//        BigDecimal user_enable_amt = user.getEnableAmt();
//        BigDecimal buy_amt = (new BigDecimal(buyPrice)).multiply(new BigDecimal(buyNum.intValue()));
//        BigDecimal buy_amt_autual = buy_amt.divide(new BigDecimal(lever.intValue()), 2, 4);
//
//
//        int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual);
//        log.info("用户可用金额 = {}  实际购买金额 =  {}", user_enable_amt, buy_amt_autual);
//        log.info("比较 用户金额 和 实际 购买金额 =  {}", Integer.valueOf(compareUserAmtInt));
//        if (compareUserAmtInt == -1) {
//            log.info("下单失败，用户可用金额小于" + buy_amt_autual + "元");
//            return ServerResponse.createByErrorMsg("The order failed, and the user's available amount is less than " + buy_amt_autual + "USD");
//
//        }
//
////        if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) {
////            log.info("失败，指数总资金小于0");
////            return ServerResponse.createByErrorMsg("失败，指数总资金小于0");
////
////        }
//
//
//        UserPosition userPosition = new UserPosition();
//
//        if (profitTarget != null && profitTarget.compareTo(BigDecimal.ZERO) > 0) {
//            userPosition.setProfitTargetPrice(profitTarget);
//        }
//        if (stopTarget != null && stopTarget.compareTo(BigDecimal.ZERO) > 0) {
//            userPosition.setStopTargetPrice(stopTarget);
//        }
//
//        userPosition.setPositionType(user.getAccountType());
//        userPosition.setPositionSn(KeyUtils.getUniqueKey());
//        userPosition.setUserId(user.getId());
//        userPosition.setNickName(user.getRealName());
//        userPosition.setAgentId(user.getAgentId());
//        userPosition.setStockCode(stStock.getCode());
//        userPosition.setStockName(stStock.getName());
//        userPosition.setStockGid(stStock.getCode());
//        userPosition.setStockSpell(stStock.getMarket());
//        userPosition.setBuyOrderId(GeneratePosition.getPositionId());
//        userPosition.setBuyOrderTime(DateTimeUtil.strToDate(buyTime));
//        userPosition.setBuyOrderPrice(new BigDecimal(buyPrice));
//        userPosition.setOrderDirection((buyType.intValue() == 0) ? "Buy Up" : "Buy Down");
//        userPosition.setOrderNum(buyNum);
//
//        if (null != market) {
//            userPosition.setStockPlate(market);
//        }
//
//
//        userPosition.setIsLock(Integer.valueOf(0));
//        userPosition.setOrderLever(lever);
//        userPosition.setOrderTotalPrice(buy_amt);
//
//        //递延费特殊处理
//        BigDecimal stayFee = userPosition.getOrderTotalPrice().multiply(siteSetting.getStayFee());
//        BigDecimal allStayFee = stayFee.multiply(new BigDecimal(1));
//        userPosition.setOrderStayFee(allStayFee);
//        userPosition.setOrderStayDays(1);
//
//
//        BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(4, BigDecimal.ROUND_HALF_UP);
//        log.info("创建模拟持仓 手续费（配资后总资金 * 百分比） = {}", buy_fee_amt);
//        userPosition.setOrderFee(buy_fee_amt);
//
//
//        BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(4, BigDecimal.ROUND_HALF_UP);
//        log.info("创建模拟持仓 印花税（配资后总资金 * 百分比） = {}", buy_yhs_amt);
//        userPosition.setOrderSpread(buy_yhs_amt);
//
//        // 使用股票新接口
//        BigDecimal now_price = new BigDecimal(BigInteger.ZERO);
//        BigDecimal stock_crease = new BigDecimal(BigInteger.ZERO);
//        StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(market, stockCode);
//        if (null != tickerDetails) {
//            StockTickerListInfo data = tickerDetails.getData();
//            if (null != data) {
//                now_price = data.getPrice();
//                stock_crease = data.getUp();
//            }
//        }
//
//
//
//        if ("BJ".equalsIgnoreCase(market) || "NASDAQ".equalsIgnoreCase(market) ){
//            now_price = now_price.setScale(4, BigDecimal.ROUND_HALF_UP);
//        } else {
//            String rate = siteSetting.getRupeesToDollarsRate();
//            BigDecimal rupeesToDollarsRate = new BigDecimal(rate);
//            now_price = now_price.multiply(rupeesToDollarsRate).setScale(4, BigDecimal.ROUND_HALF_UP);
//        }
//
//        if (now_price.compareTo(new BigDecimal("0")) == 0) {
//            log.info(stStock.getCode() + "报价0，");
//            return ServerResponse.createByErrorMsg("Quote 0, please try again later.");
//
//        }
//
//        SiteSpread siteSpread = iSiteSpreadService.findSpreadRateOne(stock_crease, buy_amt, stStock.getCode(), now_price);
//        BigDecimal spread_rate_amt = new BigDecimal("0");
//        if (siteSpread != null) {
//            spread_rate_amt = buy_amt.multiply(siteSpread.getSpreadRate()).setScale(4, BigDecimal.ROUND_HALF_UP);
//            log.info("用户购买点差费（配资后总资金 * 百分比{}） = {}", siteSpread.getSpreadRate(), spread_rate_amt);
//        } else {
//            log.info("用户购买点差费（配资后总资金 * 百分比{}） = {}", "设置异常", spread_rate_amt);
//        }
//
//        userPosition.setSpreadRatePrice(spread_rate_amt);
//        BigDecimal profit_and_lose = BigDecimal.ZERO;
//        userPosition.setProfitAndLose(profit_and_lose);
//        // 总手续费
//        BigDecimal all_profit_and_lose = profit_and_lose.subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt);
//        userPosition.setAllProfitAndLose(all_profit_and_lose);
//        userPosition.setOrderStayDays(Integer.valueOf(0));
//        userPosition.setOrderStayFee(BigDecimal.ZERO);
//        userPosition.setSpreadRatePrice(BigDecimal.ZERO);
//
//        int insertPositionCount = this.userPositionMapper.insert(userPosition);
//        if (insertPositionCount > 0) {
//            log.info("【创建持仓】保存记录成功");
//        } else {
//            log.error("【创建持仓】保存记录出错");
//        }
//
//        // 判断用户是否已经存在该股票
//        UserPosition position = this.userPositionMapper.findUserPositionByCode(user.getId(), stockCode);
//        Integer oldOrderNum = 0;
//        Integer id;
//        String positionSn;
//        // 如果已经存在该股票，那么需要进行叠加，价格取平均值
//        if (null != position) {
//            oldOrderNum = position.getOrderNum();
//            position.setBuyOrderPrice(position.getBuyOrderPrice().add(userPosition.getBuyOrderPrice()).divide(new BigDecimal("2")).setScale(2, RoundingMode.HALF_UP));
//            position.setOrderNum(userPosition.getOrderNum()+position.getOrderNum());
//            BigDecimal oldProfitTargetPrice = userPosition.getProfitTargetPrice() != null ? userPosition.getProfitTargetPrice() : BigDecimal.ZERO;
//            BigDecimal currProfitTargetPrice = position.getProfitTargetPrice() != null ? position.getProfitTargetPrice() : BigDecimal.ZERO;
//            position.setProfitTargetPrice(oldProfitTargetPrice.add(currProfitTargetPrice));
//            position.setOrderTotalPrice(position.getOrderTotalPrice().add(userPosition.getOrderTotalPrice()));
//            position.setOrderFee(position.getOrderFee().add(userPosition.getOrderFee()));
//            position.setOrderSpread(position.getOrderSpread().add(userPosition.getOrderSpread()));
//            position.setOrderStayFee(position.getOrderStayFee().add(userPosition.getOrderStayFee()));
//            position.setProfitAndLose(position.getProfitAndLose().add(userPosition.getProfitAndLose()));
//            position.setAllProfitAndLose(position.getAllProfitAndLose().add(userPosition.getAllProfitAndLose()));
//            position.setSpreadRatePrice(position.getSpreadRatePrice().add(userPosition.getSpreadRatePrice()));
//            this.userPositionMapper.updateByPrimaryKey(position);
//            id = position.getId();
//            positionSn = position.getPositionSn();
//            userPosition.setId(id);
//            userPosition.setBuyOrderId(position.getBuyOrderId());
//        } else {
//            this.userPositionMapper.insert(userPosition);
//            positionSn = userPosition.getPositionSn();
//        }
//        // 记录购买详情
//        insertPositionDetail(userPosition, oldOrderNum, 1);
//
//        BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual);
//        user.setEnableAmt(reckon_enable);
//        int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);
//        if (updateUserCount > 0) {
//            log.info("【用户交易下单】修改用户金额成功");
//        } else {
//            log.error("用户交易下单】修改用户金额出错");
//
//        }
//        iAgentAgencyFeeService.AgencyFeeIncome(1, positionSn);
//        return ServerResponse.createBySuccess("Generate a successful position");
    }


    public int deleteByUserId(Integer userId) {
        return this.userPositionMapper.deleteByUserId(userId);
    }

    public void doClosingStayTask() {
        List<UserPosition> userPositions = this.userPositionMapper.findAllStayPosition();


        if (userPositions.size() > 0) {
            log.info("查询到正在持仓的订单数量 = {}", Integer.valueOf(userPositions.size()));

            SiteProduct siteProduct = iSiteProductService.getProductSetting();
            if (!siteProduct.getHolidayDisplay()) {
                for (UserPosition position : userPositions) {
                    int stayDays = GetStayDays.getDays(GetStayDays.getBeginDate(position.getBuyOrderTime()));
                    //递延费特殊处理
                    stayDays = stayDays + 1;

                    log.info("");
                    log.info("开始处理 持仓订单id = {} 订单号 = {} 用户id = {} realName = {} 留仓天数 = {}", new Object[]{position
                            .getId(), position.getPositionSn(), position.getUserId(), position
                            .getNickName(), Integer.valueOf(stayDays)});

                    if (stayDays != 0) {
                        log.info(" 开始收取 {} 天 留仓费", Integer.valueOf(stayDays));
                        try {
                            closingStayTask(position, Integer.valueOf(stayDays));
                        } catch (Exception e) {
                            log.error("doClosingStayTask = ", e);


                        }


                    } else {


                        log.info("持仓订单 = {} ,持仓天数0天,不需要处理...", position.getId());
                    }

                    log.info("修改留仓费 处理结束。");
                    log.info("");
                }

                SiteTaskLog stl = new SiteTaskLog();
                stl.setTaskType("Deduct the retention fee");
                stl.setAddTime(new Date());
                stl.setIsSuccess(Integer.valueOf(0));
                stl.setTaskTarget("After deducting the retention fee, the order quantity is " + userPositions.size());
                this.siteTaskLogMapper.insert(stl);
            }
        } else {
            log.info("doClosingStayTask没有正在持仓的订单");
        }
    }

    /*留仓到期强制平仓，每天15点执行*/
    public void expireStayUnwindTask() {
        List<UserPosition> userPositions = this.userPositionMapper.findAllStayPosition();


        if (userPositions.size() > 0) {
            log.info("查询到正在持仓的订单数量 = {}", Integer.valueOf(userPositions.size()));

            SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
            for (UserPosition position : userPositions) {
                int stayDays = GetStayDays.getDays(GetStayDays.getBeginDate(position.getBuyOrderTime()));

                log.info("");
                log.info("开始处理 持仓订单id = {} 订单号 = {} 用户id = {} realName = {} 留仓天数 = {}", new Object[]{position
                        .getId(), position.getPositionSn(), position.getUserId(), position
                        .getNickName(), Integer.valueOf(stayDays)});

                //留仓达到最大天数
                if (stayDays >= siteSetting.getStayMaxDays().intValue()) {
                    log.info(" 开始强平 {} 天", Integer.valueOf(stayDays));
                    try {
                        this.sell(position.getPositionSn(), 0);
                    } catch (Exception e) {
                        log.error("expireStayUnwindTask = ", e);
                    }
                } else {
                    log.info("持仓订单 = {} ,持仓天数0天,不需要处理...", position.getId());
                }
            }
        } else {
            log.info("doClosingStayTask没有正在持仓的订单");
        }
    }

    @Transactional
    public ServerResponse closingStayTask(UserPosition position, Integer stayDays) throws Exception {
        log.info("=================closingStayTask====================");
        log.info("修改留仓费，持仓id={},持仓天数={}", position.getId(), stayDays);

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("修改留仓费出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("There was an error in modifying the retention fee, and the website settings table did not exist.");
        }


        BigDecimal stayFee = position.getOrderTotalPrice().multiply(siteSetting.getStayFee());

        BigDecimal allStayFee = stayFee.multiply(new BigDecimal(stayDays.intValue()));

        log.info("总留仓费 = {}", allStayFee);


        position.setOrderStayFee(allStayFee);
        position.setOrderStayDays(stayDays);

        BigDecimal all_profit = position.getAllProfitAndLose().subtract(allStayFee);
        position.setAllProfitAndLose(all_profit);

        int updateCount = this.userPositionMapper.updateByPrimaryKeySelective(position);
        if (updateCount > 0) {
            //核算代理收入-延递费
//            iAgentAgencyFeeService.AgencyFeeIncome(3, position.getPositionSn());
            log.info("【closingStayTask收持仓费】修改持仓记录成功");
        } else {
            log.error("【closingStayTask收持仓费】修改持仓记录出错");
            throw new Exception("[closingStayTask holding fee] Error in modifying the position record");
        }


        log.info("=======================================================");
        return ServerResponse.createBySuccess();
    }

    public List<Integer> findDistinctUserIdList() {
        return this.userPositionMapper.findDistinctUserIdList();
    }

    private AdminPositionVO assembleAdminPositionVO(UserPosition position) {
        AdminPositionVO adminPositionVO = new AdminPositionVO();

        Integer userId = position.getUserId();
        User user = userMapper.selectById(userId);
        if (null != user) {
            adminPositionVO.setUserPhone(user.getPhone());
        }

        adminPositionVO.setUserId(userId);
        adminPositionVO.setId(position.getId());
        adminPositionVO.setPositionSn(position.getPositionSn());
        adminPositionVO.setPositionType(position.getPositionType());
        adminPositionVO.setNickName(position.getNickName());
        adminPositionVO.setAgentId(position.getAgentId());
        adminPositionVO.setStockName(position.getStockName());
        adminPositionVO.setStockCode(position.getStockCode());
        adminPositionVO.setStockGid(position.getStockGid());
        adminPositionVO.setStockSpell(position.getStockSpell());
        adminPositionVO.setBuyOrderId(position.getBuyOrderId());
        adminPositionVO.setBuyOrderTime(position.getBuyOrderTime());
        adminPositionVO.setBuyOrderPrice(position.getBuyOrderPrice());
        adminPositionVO.setSellOrderId(position.getSellOrderId());
        adminPositionVO.setSellOrderTime(position.getSellOrderTime());
        adminPositionVO.setSellOrderPrice(position.getSellOrderPrice());
        adminPositionVO.setOrderDirection(position.getOrderDirection());
        adminPositionVO.setOrderNum(position.getOrderNum());
        adminPositionVO.setOrderLever(position.getOrderLever());
        adminPositionVO.setOrderTotalPrice(position.getOrderTotalPrice());
        adminPositionVO.setOrderFee(position.getOrderFee());
        adminPositionVO.setOrderSpread(position.getOrderSpread());
        adminPositionVO.setOrderStayFee(position.getOrderStayFee());
        adminPositionVO.setOrderStayDays(position.getOrderStayDays());

        adminPositionVO.setIsLock(position.getIsLock());
        adminPositionVO.setLockMsg(position.getLockMsg());

        adminPositionVO.setStockPlate(position.getStockPlate());

        PositionProfitVO positionProfitVO = getPositionProfitVO(position);
        adminPositionVO.setProfitAndLose(positionProfitVO.getProfitAndLose());
        adminPositionVO.setAllProfitAndLose(positionProfitVO.getAllProfitAndLose());
        adminPositionVO.setNow_price(positionProfitVO.getNowPrice());


        return adminPositionVO;
    }

    private AgentPositionVO assembleAgentPositionVO(UserPosition position) {
        AgentPositionVO agentPositionVO = new AgentPositionVO();
        Integer userId = position.getUserId();
        User user = userMapper.selectById(userId);
        if (null != user) {
            agentPositionVO.setUserPhone(user.getPhone());
        }
        agentPositionVO.setId(position.getId());
        agentPositionVO.setPositionSn(position.getPositionSn());
        agentPositionVO.setPositionType(position.getPositionType());
        agentPositionVO.setUserId(position.getUserId());
        agentPositionVO.setNickName(position.getNickName());
        agentPositionVO.setAgentId(position.getAgentId());
        agentPositionVO.setStockName(position.getStockName());
        agentPositionVO.setStockCode(position.getStockCode());
        agentPositionVO.setStockGid(position.getStockGid());
        agentPositionVO.setStockSpell(position.getStockSpell());
        agentPositionVO.setBuyOrderId(position.getBuyOrderId());
        agentPositionVO.setBuyOrderTime(position.getBuyOrderTime());
        agentPositionVO.setBuyOrderPrice(position.getBuyOrderPrice());
        agentPositionVO.setSellOrderId(position.getSellOrderId());
        agentPositionVO.setSellOrderTime(position.getSellOrderTime());
        agentPositionVO.setSellOrderPrice(position.getSellOrderPrice());
        agentPositionVO.setOrderDirection(position.getOrderDirection());
        agentPositionVO.setOrderNum(position.getOrderNum());
        agentPositionVO.setOrderLever(position.getOrderLever());
        agentPositionVO.setOrderTotalPrice(position.getOrderTotalPrice());
        agentPositionVO.setOrderFee(position.getOrderFee());
        agentPositionVO.setOrderSpread(position.getOrderSpread());
        agentPositionVO.setOrderStayFee(position.getOrderStayFee());
        agentPositionVO.setOrderStayDays(position.getOrderStayDays());

        agentPositionVO.setIsLock(position.getIsLock());
        agentPositionVO.setLockMsg(position.getLockMsg());

        agentPositionVO.setStockPlate(position.getStockPlate());

        PositionProfitVO positionProfitVO = getPositionProfitVO(position);
        agentPositionVO.setProfitAndLose(positionProfitVO.getProfitAndLose());
        agentPositionVO.setAllProfitAndLose(positionProfitVO.getAllProfitAndLose());
        agentPositionVO.setNow_price(positionProfitVO.getNowPrice());


        return agentPositionVO;
    }

    private UserPositionVO assembleUserPositionVO(UserPosition position) {
        UserPositionVO userPositionVO = new UserPositionVO();

        userPositionVO.setId(position.getId());
        userPositionVO.setPositionType(position.getPositionType());
        userPositionVO.setPositionSn(position.getPositionSn());
        userPositionVO.setUserId(position.getUserId());
        userPositionVO.setNickName(position.getNickName());
        userPositionVO.setAgentId(position.getAgentId());
        userPositionVO.setStockName(position.getStockName());
        userPositionVO.setStockCode(position.getStockCode());
        userPositionVO.setStockGid(position.getStockGid());
        userPositionVO.setStockSpell(position.getStockSpell());
        userPositionVO.setBuyOrderId(position.getBuyOrderId());
        userPositionVO.setBuyOrderTime(position.getBuyOrderTime());
        userPositionVO.setBuyOrderPrice(position.getBuyOrderPrice());
        userPositionVO.setSellOrderId(position.getSellOrderId());
        userPositionVO.setSellOrderTime(position.getSellOrderTime());
        userPositionVO.setSellOrderPrice(position.getSellOrderPrice());
        userPositionVO.setProfitTargetPrice(position.getProfitTargetPrice());
        userPositionVO.setStopTargetPrice(position.getStopTargetPrice());
        userPositionVO.setOrderDirection(position.getOrderDirection());
        userPositionVO.setOrderNum(position.getOrderNum());
        userPositionVO.setOrderLever(position.getOrderLever());
        userPositionVO.setOrderTotalPrice(position.getOrderTotalPrice());
        userPositionVO.setOrderFee(position.getOrderFee());
        userPositionVO.setOrderSpread(position.getOrderSpread());
        userPositionVO.setOrderStayFee(position.getOrderStayFee());
        userPositionVO.setOrderStayDays(position.getOrderStayDays());
        userPositionVO.setMarginAdd(position.getMarginAdd());
        userPositionVO.setInitPrice(position.getInitPrice());
        userPositionVO.setStockPlate(position.getStockPlate());
        userPositionVO.setSpreadRatePrice(position.getSpreadRatePrice());

        PositionProfitVO positionProfitVO = getPositionProfitVO(position);
        userPositionVO.setProfitAndLose(positionProfitVO.getProfitAndLose());
        userPositionVO.setAllProfitAndLose(positionProfitVO.getAllProfitAndLose());
        userPositionVO.setNowPrice(new BigDecimal(positionProfitVO.getNowPrice()));

        userPositionVO.setMarket(positionProfitVO.getMarket());

        return userPositionVO;
    }

    public PositionProfitVO getPositionProfitVO(UserPosition position) {
        BigDecimal profitAndLose = new BigDecimal(BigInteger.ZERO);
        BigDecimal allProfitAndLose = new BigDecimal(BigInteger.ZERO);
        BigDecimal nowPrice = new BigDecimal(BigInteger.ZERO);

        PositionProfitVO positionProfitVO = new PositionProfitVO();
        positionProfitVO.setAllProfitAndLose(allProfitAndLose);
        positionProfitVO.setProfitAndLose(profitAndLose);
        positionProfitVO.setNowPrice(String.valueOf(nowPrice));
        positionProfitVO.setMarket(position.getStockSpell());

        String stockCode = position.getStockCode();
        String stockSpell = position.getStockSpell();
        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
        stockQueryWrapper.eq("code", stockCode);
        stockQueryWrapper.eq("market", stockSpell);
        List<StStock> stStocks = stStockMapper.selectList(stockQueryWrapper);

        StStock stStock = null;
        if(!stStocks.isEmpty()){
            stStock = stStocks.get(0);
        }


        // 使用新版数据
        if (null == stStock) {
            log.info("下单失败，股票不存在！");
            return positionProfitVO;
        }
        String market = stStock.getMarket();

        // 查询该股票的实时价格
        StStockTickerDetails tickerDetails = stocksComponent.queryDetailsByMarketAndCode(market, stockCode);
        if (null == tickerDetails) {
            log.info("Failed to query the real-time price of stocks！【tickerDetails】");
            return positionProfitVO;
        }

        StockTickerListInfo tickerInfo = tickerDetails.getData();
        if (null == tickerInfo) {
            log.info("Failed to query the real-time price of stocks！【tickerInfo】");
            return positionProfitVO;
        }

        nowPrice = tickerInfo.getPrice();
        BigDecimal initPrice = position.getInitPrice();
        BigDecimal subPrice = nowPrice.subtract(initPrice);

        // 印度股票
//        if ("SH".equalsIgnoreCase(market) || "SZ".equalsIgnoreCase(market) ){
//            SiteSetting siteSetting = iSiteSettingService.getSiteSetting();
//            subPrice = subPrice.multiply(new BigDecimal(siteSetting.getRupeesToDollarsRate())).setScale(6, BigDecimal.ROUND_HALF_UP);
//        }

        profitAndLose = subPrice.multiply(new BigDecimal(position.getOrderNum().intValue()));


        // 计算所有相关费用的总和，包括订单费用、交易费差和停留费等，并将结果存储在 total_fee 变量中。
        BigDecimal total_fee = position.getOrderFee();
        // 计算扣除了总费用后的实际盈亏，并将结果存储在 position_profit 变量中。
        BigDecimal position_profit = profitAndLose.subtract(total_fee);
        //总盈亏 = 浮动盈亏 – 总手续费
        allProfitAndLose = allProfitAndLose.add(position_profit);


        positionProfitVO.setProfitAndLose(position_profit);
        positionProfitVO.setAllProfitAndLose(allProfitAndLose);
        positionProfitVO.setNowPrice(nowPrice.toString());
        return positionProfitVO;
    }


    /*股票入仓最新top列表*/
    public ServerResponse findPositionTopList(Integer pageSize) {
        List<UserPosition> userPositions = this.userPositionMapper.findPositionTopList(pageSize);

        List<UserPositionVO> userPositionVOS = Lists.newArrayList();
        if (userPositions.size() > 0) {
            for (UserPosition position : userPositions) {

                UserPositionVO userPositionVO = assembleUserPositionVO(position);
                userPositionVOS.add(userPositionVO);
            }
        }

        PageInfo pageInfo = new PageInfo(userPositions);
        pageInfo.setList(userPositionVOS);

        return ServerResponse.createBySuccess(pageInfo);
    }

    /*根据股票代码查询用户最早入仓股票*/
    public ServerResponse findUserPositionByCode(HttpServletRequest request, String stockCode) {
        User user = this.iUserService.getCurrentRefreshUser(request);
        UserPosition position = this.userPositionMapper.findUserPositionByCode(user.getId(), stockCode);

        List<UserPositionVO> userPositionVOS = Lists.newArrayList();
        UserPositionVO userPositionVO = null;
        if (position != null) {
            userPositionVO = assembleUserPositionVO(position);
        }
        userPositionVOS.add(userPositionVO);

        PageInfo pageInfo = new PageInfo();
        pageInfo.setList(userPositionVOS);

        return ServerResponse.createBySuccess(pageInfo);
    }

    @Override
    public ServerResponse getHoldNumById(HttpServletRequest httpServletRequest, String stockCode) {
        User user = this.iUserService.getCurrentRefreshUser(httpServletRequest);
        UserPosition userPosition = this.userPositionMapper.findUserPositionByCode(user.getId(), stockCode);
        if(null == userPosition){
            Map<String, Integer> map = new HashMap<>();
            map.put("holdNum", 0);
            return ServerResponse.createBySuccess(map);
        }

        val orderNum = userPosition.getOrderNum();
        val sellouts = this.userPendingorderMapper.listSellOrderByStockIdAndUserId(user.getId(), stockCode);
        val sum = sellouts.stream().mapToInt(UserPendingorder::getBuyNum).sum();
        if (orderNum.intValue() - sum <= 0) {
            Map<String, Integer> map = new HashMap<>();
            map.put("holdNum", 0);
            return ServerResponse.createBySuccess(map);
        }
        Map<String, Integer> map = new HashMap<>();
        map.put("holdNum", (orderNum.intValue() - sum));
        return ServerResponse.createBySuccess(map);
    }


    /**
     * 获取股票交易记录
     * @param httpServletRequest
     * @return
     */
    @Override
    public ServerResponse listPositionDetail(Integer pageNum, Integer pageSize, HttpServletRequest httpServletRequest) {
        // 分页
        Page<Object> page = PageHelper.startPage(pageNum, pageSize);

        User user = this.iUserService.getCurrentRefreshUser(httpServletRequest);
        if (null == user) {
            return ServerResponse.createByErrorMsg("Please log in and check the record.");
        }

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("下单出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("The order failed, and the system settings are wrong.");
        }

        List<UserPositionDetailVo> details = userPositionDetailMapper.listPositionDetail(user.getId());
        for (UserPositionDetailVo detail : details) {
            String market = detail.getMarket();
            String code = detail.getStockCode();

            // 卖出的时候需要计算亏盈数字和百分比
            String type = detail.getType();
            // String typeStr = String.valueOf(type);
            if (UserPositionDetailVo.TYPE_SELL.equals(type)) {
                // 总订单购买价格 - 多次购买取平均数
                BigDecimal parentOrderPrice = detail.getParentOrderPrice();
                // 卖出时的价格
                BigDecimal orderPrice = detail.getInitPrice();

                // 计算盈亏  卖出的价格减去总订单购买的平均价格
                BigDecimal profit = orderPrice.subtract(parentOrderPrice);
//                if ("SH".equalsIgnoreCase(market) || "SZ".equalsIgnoreCase(market) ){
//                    profit = profit.multiply(new BigDecimal(siteSetting.getRupeesToDollarsRate())).setScale(6, RoundingMode.HALF_UP);
//                }

                // 单股的盈亏乘以卖出的数量得出本次卖出的总盈亏
                BigDecimal change = profit.multiply(new BigDecimal(detail.getOrderNum()));
                detail.setChange(change);

                // 涨幅百分比   购买价格和当前最新的价格的比例
                BigDecimal up = orderPrice.subtract(parentOrderPrice)
                        .divide(parentOrderPrice, 6, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100));
                detail.setUp(up);
            }
            else {
                // 成本应该就是购买金额 + 手续费吧
                BigDecimal cost = detail.getOrderTotalPrice().add(detail.getAllProfitAndLose());
                detail.setCost(cost);
            }

        }

        PageInfo pageInfo = new PageInfo(details);
        pageInfo.setList(details);
        return ServerResponse.createBySuccess(pageInfo);

    }


    /**
     * 获取第一个交易所
     * @param exchange
     */
    private String getFirstMarket(String exchange){
        if (!exchange.contains(",")){
            exchange = exchange.replace(" ", ", ");
        }
        String[] a = exchange.split(",");
        exchange = a[0];
        return exchange;
    }

    /**
     * @Description: 新股转持仓
     * @Param: newCode 页面传过来的股票代码
     * @return:
     * @Author: tf
     * @Date: 2022/10/26
     */
    @Override
    @Transactional
    public ServerResponse newStockToPosition(Integer id, String newCode) {
        UserStockSubscribe userStockSubscribe = userStockSubscribeMapper.load(id);
        if (null == userStockSubscribe) {
            return ServerResponse.createByErrorMsg("无申购记录");
        }

        // 获取新股股票
        StIpo stIpo = stIpoService.getById(userStockSubscribe.getIpoId());
        if (null == stIpo) {
            return ServerResponse.createByErrorMsg("新股不存在.");
        }
        // 判断当前状态是否为中签，不是则直接返回
        if (userStockSubscribe.getStatus() != 3){
            return ServerResponse.createByErrorMsg("当前状态不是中签状态，无法转持仓.");
        }
        // 判断当前时间是否已经上市
        try {
            Date listingDate = DateUtils.parseDate(stIpo.getListingDate(), "yyyy-MM-dd");
            Date currDate = new Date();
            if (listingDate.compareTo(currDate) > 0) {
                return ServerResponse.createByErrorMsg("当前股票尚未上市.");
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }


        // 获取交易所
        String exchange = getFirstMarket(stIpo.getExchange());

        // 根据交易所和股票代码查询数据库是否已经存在股票数据
//        QueryWrapper queryWrapper = new QueryWrapper();
//        queryWrapper.eq("symbol", newCode);
//        queryWrapper.eq("exchange", stIpo.getExchange());
//        queryWrapper.le("listing_date", DateUtils.formatDate(new Date()));
//        StIpo ipo = stIpoService.getOne(queryWrapper);
//        if (null != ipo && !ipo.getId().equals(stIpo.getId())) {
//            return ServerResponse.createByErrorMsg("You enter the stock code is other has launched new code, please try again.");
//        }

        // 如果不存在则实时查询新股数据
        StStockTickerDetails stockTickerDetail = stocksComponent.queryDetailsByMarketAndCode(exchange, newCode);
        if (null == stockTickerDetail && null == stockTickerDetail.getData()) {
            return ServerResponse.createByErrorMsg("您输入的股票代码不存在.");
        }

        // 使用新版股票数据
//        QueryWrapper<StStock> stockQueryWrapper = new QueryWrapper<>();
//        stockQueryWrapper.eq("code", newCode);
//        stockQueryWrapper.eq("market", exchange);
//        StStock stStock = stStockMapper.selectOne(stockQueryWrapper);
//        if (null == stStock) {
//            return ServerResponse.createByErrorMsg("The order failed, and the stock does not exist！");
//        }

        // 修改st_ipo表的股票代码
        stIpo.setSymbol(stockTickerDetail.getCode());
        stIpoService.updateById(stIpo);

        // 修改 user_stock_subscribe 表的股票代码
        userStockSubscribe.setNewCode(stockTickerDetail.getCode());
        userStockSubscribeMapper.updateById(userStockSubscribe);

        // 转持仓，调用购买逻辑
        if (userStockSubscribe.getStatus() == 3) {
            User user = userMapper.selectById(userStockSubscribe.getUserId());
            Integer buyNum = userStockSubscribe.getApplyNumber();
//            if(SystemVersionEnum.india.name().equals(active)) {
//                buyNum = userStockSubscribe.getApplyNums();
//            }

            // 校验支付密码
            String userPayPwd = user.getPayPwd();
            if (StringUtils.isBlank(userPayPwd)) {
                return ServerResponse.createByErrorMsg("您尚未设置支付密码，请先设置支付密码");
            }

            /*实名认证开关开启*/
            SiteProduct siteProduct = iSiteProductService.getProductSetting();

            // 是否是盘前交易
            boolean isBefore = false;
            int beforeFlag = 0;
            StPremarketStock stPremarketStock = new StPremarketStock();

            if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
                return ServerResponse.createByErrorMsg("订单失败，请先进行实名认证.");
            }

            if (siteProduct.getRealNameDisplay() && user.getIsLock() == 1) {
                return ServerResponse.createByErrorMsg("订单失败，账户被锁定");
            }

            SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
            if (siteSetting == null) {
                log.error("下单出错，网站设置表不存在");
                return ServerResponse.createByErrorMsg("下单出错，网站设置表不存在.");
            }

            // 调用实际购买方法
//            ServerResponse response = actualPurchase(user, newCode, exchange, buyNum, 0, 1,
//                    BigDecimal.ZERO, BigDecimal.ZERO, StockBuyTypeEnum.NEW_BUY.getType(), SymmetricCryptoUtil.decryptPassword(user.getPayPwd()));


            // 涨跌幅
            BigDecimal up = BigDecimal.ZERO;
            // 收盘价
            BigDecimal zsPrice = BigDecimal.ZERO;
            // 原始价格
            BigDecimal initPrice = new BigDecimal(stIpo.getIssuePrice());
            BigDecimal now_price = initPrice;

            if (now_price.compareTo(BigDecimal.ZERO) == 0) {
                return ServerResponse.createByErrorMsg("当前行情为0，请稍后再试。");
            }

            double stock_crease = up.doubleValue();

            BigDecimal maxRisePercent = up;
            maxRisePercent = maxRisePercent.divide(new BigDecimal(100)).setScale(6, RoundingMode.HALF_UP);

            // 计算购买总额。这行代码将当前价格 now_price 乘以购买数量 buyNum，得到了购买总额 buy_amt。
            BigDecimal buy_amt = now_price.multiply(new BigDecimal(buyNum)).setScale(6, RoundingMode.HALF_UP);
            // 计算实际购买总额。
            BigDecimal buy_amt_autual = buy_amt;

            /**
             * 用户可用金额
             */
            BigDecimal user_enable_amt = user.getEnableAmt();
            // 配资金额
            BigDecimal tradingAmount = user.getTradingAmount();
            // 检查实际购买总额是否超过了用户可用资金的最大允许比例 (可用资金 = 配资资金+用户现金)
            BigDecimal availableFunds = user_enable_amt.add(tradingAmount);

            log.info("用户id = {} 可用金额 = {} 实际购买金额 =  {}",user.getId(), availableFunds, buy_amt_autual);

            // 股票名称
            String stockName = stockTickerDetail.getData().getName();
            // 存储股票购买信息
            UserPosition userPosition = new UserPosition();
            userPosition.setInitPrice(initPrice);
            userPosition.setPositionType(user.getAccountType());
            userPosition.setPositionSn(KeyUtils.getUniqueKey());
            userPosition.setUserId(user.getId());
            userPosition.setNickName(user.getRealName());
            userPosition.setAgentId(user.getAgentId());
            userPosition.setStockCode(newCode);
            userPosition.setStockName(stockName);
            userPosition.setStockGid(exchange);
            userPosition.setStockSpell(exchange);
            userPosition.setStockPlate(exchange);
            userPosition.setBuyOrderId(GeneratePosition.getPositionId());
            userPosition.setBuyOrderTime(new Date());
            userPosition.setBuyOrderPrice(now_price);
            userPosition.setOrderDirection("Buy Up");
            userPosition.setOrderNum(buyNum);
            userPosition.setIsLock(0);
            userPosition.setOrderLever(1);
            userPosition.setOrderTotalPrice(buy_amt);

            //递延费特殊处理
            BigDecimal stayFee = userPosition.getOrderTotalPrice().multiply(siteSetting.getStayFee());
            userPosition.setOrderStayFee(BigDecimal.ZERO);
            userPosition.setOrderStayDays(0);
            // 印花税
            BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(6, RoundingMode.HALF_UP);
            log.info("用户id = {} 购买印花税（配资后总资金 * 百分比） = {}", user.getId(), buy_yhs_amt);
            userPosition.setOrderSpread(BigDecimal.ZERO);
            // 点差费
            SiteSpread siteSpread = iSiteSpreadService.findSpreadRateOne(new BigDecimal(stock_crease), buy_amt, newCode, now_price);
            BigDecimal spread_rate_amt = BigDecimal.ZERO;
            if (siteSpread != null) {
                spread_rate_amt = buy_amt.multiply(siteSpread.getSpreadRate()).setScale(6, RoundingMode.HALF_UP);
                log.info("用户id = {} 购买点差费（配资后总资金 * 百分比{}） = {}",user.getId(), siteSpread.getSpreadRate(), spread_rate_amt);
            } else {
                log.info("用户id = {} 购买点差费（配资后总资金 * 百分比{}） = {}", "设置异常",user.getId(), spread_rate_amt);
            }
            userPosition.setSpreadRatePrice(BigDecimal.ZERO);

            // IPO 不需要手续费
            BigDecimal buy_fee_amt = BigDecimal.ZERO;
            log.info("用户id = {} 购买手续费（配资后总资金 * 百分比） = {}", user.getId(), buy_fee_amt);
            userPosition.setOrderFee(buy_fee_amt);
            // 设置盈亏
            BigDecimal profit_and_lose = BigDecimal.ZERO;
            // 设置浮动盈亏 初始时是0
            userPosition.setProfitAndLose(profit_and_lose);

            // 设置总盈亏  包括手续费 印花税 点差费  这块在购买的时候已经扣除了
            BigDecimal all_profit_and_lose = profit_and_lose.subtract(buy_fee_amt);
            userPosition.setAllProfitAndLose(all_profit_and_lose);

            // 购买金额 = 当前价格 * 数量 + 手续费
//            buy_amt_autual = buy_amt_autual.add(buy_fee_amt);

            // 判断用户是否已经存在该股票
            UserPosition position = this.userPositionMapper.findUserPositionByCode(user.getId(), newCode);
            Integer oldOrderNum = 0;
            // 如果已经存在该股票，那么需要进行叠加，价格取平均值
            if (null != position) {
                oldOrderNum = position.getOrderNum();
                position.setInitPrice(position.getInitPrice().add(userPosition.getInitPrice()).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP));
                position.setBuyOrderPrice(position.getBuyOrderPrice().add(userPosition.getBuyOrderPrice()).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP));
                position.setOrderNum(userPosition.getOrderNum()+position.getOrderNum());
                BigDecimal oldProfitTargetPrice = userPosition.getProfitTargetPrice() != null ? userPosition.getProfitTargetPrice() : BigDecimal.ZERO;
                BigDecimal currProfitTargetPrice = position.getProfitTargetPrice() != null ? position.getProfitTargetPrice() : BigDecimal.ZERO;
                position.setProfitTargetPrice(oldProfitTargetPrice.add(currProfitTargetPrice));
                position.setOrderTotalPrice(position.getOrderTotalPrice().add(userPosition.getOrderTotalPrice()));
                position.setOrderFee(position.getOrderFee().add(userPosition.getOrderFee()));
                position.setOrderSpread(position.getOrderSpread().add(userPosition.getOrderSpread()));
                position.setOrderStayFee(position.getOrderStayFee().add(userPosition.getOrderStayFee()));
                position.setProfitAndLose(position.getProfitAndLose().add(userPosition.getProfitAndLose()));
                position.setAllProfitAndLose(position.getAllProfitAndLose().add(userPosition.getAllProfitAndLose()));
                position.setSpreadRatePrice(position.getSpreadRatePrice().add(userPosition.getSpreadRatePrice()));
                this.userPositionMapper.updateByPrimaryKey(position);
                userPosition.setId(position.getId());
                userPosition.setBuyOrderId(position.getBuyOrderId());
            } else {
                this.userPositionMapper.insert(userPosition);
                userPosition.setId(userPosition.getId());
            }

            Integer stockType = StockBuyTypeEnum.NEW_BUY.getType();
            // 记录购买详情
            int detailId = insertPositionDetail(userPosition, oldOrderNum, 1, stockType);
            if (detailId > 0) {
//               if (StockBuyTypeEnum.NEW_BUY.getType().equals(stockType)) {
                    // 如果是新股申购，则需要先将金额退回到可用余额，并且冻结金额扣除
//                   BigDecimal bond = userStockSubscribe.getBond();
//                   BigDecimal djzj = user.getDjzj();
//                   djzj = djzj.subtract(bond);
//                   if (djzj.compareTo(BigDecimal.ZERO) <= 0) {
//                       djzj = new BigDecimal(BigInteger.ZERO);
//                   }
//                   user.setDjzj(djzj);
//                   User updateUser = new User();
//                   updateUser.setId(user.getId());
//                   updateUser.setDjzj(djzj);
//                   userMapper.updateByPrimaryKeySelective(updateUser);
//                }

                User currentUser = userMapper.selectById(user.getId());
                // 存储资金记录
                UserCashDetail ucd = new UserCashDetail();
                ucd.setPositionId(userPosition.getId());
                ucd.setAgentId(user.getAgentId());
                ucd.setAgentName(user.getAgentName());
                ucd.setUserId(user.getId());
                ucd.setUserName(user.getRealName());
                ucd.setDeType("IPO转持仓");
                ucd.setDeAmt(BigDecimal.ZERO);
                ucd.setDeSummary(user.getNickName() + " IPO转持仓，" + userPosition.getStockCode() + "/" + userPosition.getStockName()
                        + ", buy_amt_autual：" + 0 + ", buy_fee_amt：" + 0 + ", 可用资金: " + currentUser.getEnableAmt() + ", 冻结资金: " + currentUser.getDjzj() + ", 交易金额: " + currentUser.getTradingAmount());
                ucd.setAddTime(new Date());
                ucd.setIsRead(Integer.valueOf(0));

                int insertSxfCount = this.userCashDetailMapper.insert(ucd);
                if (insertSxfCount > 0) {
                    log.info("【用户买入股票】保存明细记录成功");
                } else {
                    log.error("用户买入股票】保存明细记录出错");
                }

                log.info("【用户交易下单】保存持仓记录成功");
                // 购买时发送邮件提醒
                if(SystemVersionEnum.global.name().equals(active)) {
                    UserPositionDetail positionDetail = userPositionDetailMapper.selectById(detailId);
                    sendHTMLMail.sendTradingBehaviorEmail(user, positionDetail);
                }
            } else {
                log.error("用户交易下单】保存持仓记录出错");
                return ServerResponse.createByErrorMsg("[用户交易订单] 保存股票记录时出错");
            }

            userStockSubscribe.setStatus(5);
            userStockSubscribeMapper.update1(userStockSubscribe);
            return ServerResponse.createBySuccessMsg("新股成功转为持仓");
        }
        return ServerResponse.createByErrorMsg("新股转为持仓失败");
    }

    public ServerResponse buyStockDzList(HttpServletRequest request) {
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (user == null) {
            return null;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("user_id", user.getId());
        param.put("position_type", 3);
        List<UserPosition> dzList = userPositionMapper.selectList(param);
        return ServerResponse.createBySuccess(dzList);

    }


    /**
     * 大宗下单
     *
     * @param stockCode
     * @param password
     * @param num
     * @param request
     * @return
     */
    @Transactional
    public ServerResponse buyDz(String stockCode, String password, Integer num, HttpServletRequest request) throws Exception {

        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
            return ServerResponse.createByErrorMsg("If the order fails, please authenticate with your real name first.");
        }
        BigDecimal user_enable_amt = user.getEnableAmt();
        log.info("用户 {} 下单，股票code = {} ，数量 = {}", new Object[]{user
                .getId(), stockCode, num});
        if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
            return ServerResponse.createByErrorMsg("Order failed and account locked");
        }

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("下单出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("The order failed, and the system settings are wrong.");
        }
        StockDz stockDz = this.stockDzMapper.selectOne(new QueryWrapper<StockDz>().eq("stock_code", stockCode));
        String am_begin = siteSetting.getTransAmBeginhk();
        String am_end = siteSetting.getTransAmEndhk();
        String pm_begin = siteSetting.getTransPmBeginhk();
        String pm_end = siteSetting.getTransPmEndhk();
        boolean am_flag = BuyAndSellUtils.isTransTime(am_begin, am_end);
        boolean pm_flag = BuyAndSellUtils.isTransTime(pm_begin, pm_end);
        log.info("是否在大宗交易时间 = {}", Boolean.valueOf(pm_flag));
        //15-15:30
//        if (!pm_flag) {
//            return ServerResponse.createByErrorMsg("下单失败，不在交易时段内");
//        }
        // 判断是否在后台设置中，如果在，则不允许购买
        if (isHoliday()) {
            return ServerResponse.createByErrorMsg("It cannot be traded on weekends or holidays.");
        }
        if (!Objects.equals(stockDz.getPassword(), password)) {
            return ServerResponse.createByErrorMsg("The order failed, and the key was wrong.");
        }

        if (stockDz.getIsLock().intValue() != 0) {
            return ServerResponse.createByErrorMsg("The order failed, and the current stock cannot be traded.");
        }

        List dbPosition = findPositionByStockCodeAndTimes(siteSetting.getBuySameTimes().intValue(), stockDz.getStockCode(), user.getId());
        if (dbPosition.size() >= siteSetting.getBuySameNums().intValue()) {
            return ServerResponse.createByErrorMsg("Frequent transactions , The position of the same stock within " + siteSetting.getBuySameTimes() + " minute shall not exceed " + siteSetting
                    .getBuySameNums() + "shares");
        }

        Integer transNum = findPositionNumByTimes(siteSetting.getBuyNumTimes().intValue(), user.getId());
        if (transNum.intValue() / 100 >= siteSetting.getBuyNumLots().intValue()) {
            return ServerResponse.createByErrorMsg("Frequent transactions, The position of the same stock within" + siteSetting
                    .getBuyNumTimes()  + " minute shall not exceed " + siteSetting.getBuyNumLots() + "hands");
        }

        if (num < stockDz.getStockNum().intValue()) {
            return ServerResponse.createByErrorMsg("The order failed, and the minimum purchase quantity is " + stockDz.getStockNum() + "share");
        }
        if (num > siteSetting.getBuyMaxNum()) {
            return ServerResponse.createByErrorMsg("The order failed, and the purchase quantity was greater than " + siteSetting.getBuyMaxNum() + "share");
        }
        BigDecimal now_price;
        StockListVO stockListVO = new StockListVO();
        //价格处理
        stockListVO = SinaStockApi.assembleStockListVO(SinaStockApi.getSinaStock(stockDz.getStockGid()));
        now_price = new BigDecimal(stockListVO.getNowPrice()).multiply(stockDz.getDiscount());

        if (now_price.compareTo(new BigDecimal("0")) == 0) {
            return ServerResponse.createByErrorMsg("Quote 0, please try again later.");
        }


        double stock_crease = stockListVO.getHcrate().doubleValue();


        BigDecimal maxRisePercent = new BigDecimal("0");
        if (stockDz.getStockPlate() != null) {

            maxRisePercent = new BigDecimal("0.2");
            log.info("【科创股票】");
        } else {
            maxRisePercent = new BigDecimal("0.1");
            log.info("【普通A股】");
        }

        if (stockListVO.getName().startsWith("ST") || stockListVO.getName().endsWith("退")) {
            return ServerResponse.createByErrorMsg("ST and delisted stocks cannot be entered.");
        }

        BigDecimal zsPrice = new BigDecimal(stockListVO.getPreclose_px());

        BigDecimal ztPrice = zsPrice.multiply(maxRisePercent).add(zsPrice);
        ztPrice = ztPrice.setScale(6, BigDecimal.ROUND_HALF_UP);
        BigDecimal chaPrice = ztPrice.subtract(zsPrice);

        BigDecimal ztRate = chaPrice.multiply(new BigDecimal("100")).divide(zsPrice, 2, 4);

        log.info("当前涨跌幅 = {} % , 涨停幅度 = {} %", Double.valueOf(stock_crease), ztRate);


        if (stockDz.getStockPlate() == null || StringUtils.isEmpty(stockDz.getStockPlate())) {

            int maxcrease = siteSetting.getCreaseMaxPercent().intValue();
            int maxDecrease = siteSetting.getDecreaseMaxPercent().intValue();

            if (stock_crease > 0.0D &&
                    stock_crease >= maxcrease) {
                return ServerResponse.createByErrorMsg("The order failed, and the stock is currently rising:" + stock_crease + ",Greater than the maximum increase:" + maxcrease);
            }

            if (stock_crease < 0.0D &&
                    -stock_crease > maxDecrease) {
                return ServerResponse.createByErrorMsg("The order failed, and the stock is currently falling:" + stock_crease + ",Greater than the biggest drop:" + maxDecrease);

            }

        } else if ("创业".equals(stockDz.getStockPlate())) {

            int maxcrease = siteSetting.getCyCreaseMaxPercent().intValue();
            int maxDecrease = siteSetting.getCyDecreaseMaxPercent().intValue();

            if (stock_crease > 0.0D &&
                    stock_crease >= maxcrease) {
                return ServerResponse.createByErrorMsg("The order failed, and the stock is currently rising:" + stock_crease + ",Greater than the maximum increase:" + maxcrease);
            }

            if (stock_crease < 0.0D &&
                    -stock_crease > maxDecrease) {
                return ServerResponse.createByErrorMsg("The order failed, and the stock is currently falling:" + stock_crease + ",Greater than the biggest drop:" + maxDecrease);
            }
        } else {

            int maxcrease = siteSetting.getKcCreaseMaxPercent().intValue();
            int maxDecrease = siteSetting.getKcDecreaseMaxPercent().intValue();

            if (stock_crease > 0.0D &&
                    stock_crease >= maxcrease) {
                return ServerResponse.createByErrorMsg("The order failed, and the stock is currently rising:" + stock_crease + ",Greater than the maximum increase:" + maxcrease);
            }

            if (stock_crease < 0.0D &&
                    -stock_crease > maxDecrease) {
                return ServerResponse.createByErrorMsg("The order failed, and the stock is currently rising:" + stock_crease + ",Greater than the biggest drop:" + maxDecrease);
            }
        }


        ServerResponse serverResponse = this.iStockService.selectRateByDaysAndStockCode(stockDz.getStockCode(), siteSetting.getStockDays().intValue());
        if (!serverResponse.isSuccess()) {
            return serverResponse;
        }
        BigDecimal daysRate = (BigDecimal) serverResponse.getData();
        log.info("股票 {} ， {} 天内 涨幅 {} , 设置的涨幅 = {}", new Object[]{stockDz.getStockCode(), siteSetting
                .getStockDays(), daysRate, siteSetting.getStockRate()});

        if (daysRate != null && siteSetting.getStockRate().compareTo(daysRate) == -1) {
            return ServerResponse.createByErrorMsg("The increase exceeded in " + siteSetting.getStockDays() + "days." + siteSetting
                    .getStockRate() + "Can't trade");
        }


        //BigDecimal buy_amt = now_price.multiply(new BigDecimal(buyNum.intValue())).divide(new BigDecimal(lever.intValue())).setScale(4, BigDecimal.ROUND_HALF_UP);
        BigDecimal buy_amt = now_price.multiply(new BigDecimal(num.intValue()));


        //BigDecimal buy_amt_autual = now_price.multiply(new BigDecimal(buyNum.intValue())).divide(new BigDecimal(lever.intValue()), 2, 4);
        BigDecimal buy_amt_autual = buy_amt.divide(new BigDecimal(1), 2, 4);


        int compareInt = buy_amt_autual.compareTo(new BigDecimal(siteSetting.getBuyMinAmt().intValue()));
        if (compareInt == -1) {
            return ServerResponse.createByErrorMsg("The order failed, and the purchase amount was less than " + siteSetting
                    .getBuyMinAmt() + "USD");
        }


        BigDecimal max_buy_amt = user_enable_amt.multiply(siteSetting.getBuyMaxAmtPercent());
        int compareCwInt = buy_amt_autual.compareTo(max_buy_amt);
        if (compareCwInt == 1) {
            return ServerResponse.createByErrorMsg("If the order fails, it cannot exceed the available funds." + siteSetting
                    .getBuyMaxAmtPercent().multiply(new BigDecimal("100")) + "%");
        }


        int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual);
        log.info("用户可用金额 = {}  实际购买金额 =  {}", user_enable_amt, buy_amt_autual);
        log.info("比较 用户金额 和 实际 购买金额 =  {}", Integer.valueOf(compareUserAmtInt));
        if (compareUserAmtInt == -1) {
            return ServerResponse.createByErrorMsg("If the order fails, the financing credit is less than " + buy_amt_autual + "USD");
        }

//        if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) {
//            return ServerResponse.createByErrorMsg("失败，指数总资金小于0");
//        }
//
        UserPosition userPosition = new UserPosition();
        userPosition.setPositionType(3);
        userPosition.setPositionSn(KeyUtils.getUniqueKey());
        userPosition.setUserId(user.getId());
        userPosition.setNickName(user.getRealName());
        userPosition.setAgentId(user.getAgentId());
        userPosition.setStockCode(stockDz.getStockCode());
        userPosition.setStockName(stockDz.getStockName());
        userPosition.setStockGid(stockDz.getStockGid());
        userPosition.setStockSpell(GetPyByChinese.converterToFirstSpell(stockDz.getStockName()));
        userPosition.setBuyOrderId(GeneratePosition.getPositionId());
        userPosition.setBuyOrderTime(new Date());
        userPosition.setBuyOrderPrice(now_price);
        userPosition.setOrderDirection("Buy Up");
        userPosition.setOrderNum(num);
        if (stockDz.getStockPlate() != null) {
            userPosition.setStockPlate(stockDz.getStockPlate());
        }
        userPosition.setIsLock(Integer.valueOf(0));
        userPosition.setOrderLever(1);
        userPosition.setOrderTotalPrice(buy_amt);

        //递延费特殊处理
        BigDecimal stayFee = userPosition.getOrderTotalPrice().multiply(siteSetting.getStayFee());
        BigDecimal allStayFee = stayFee.multiply(new BigDecimal(1));
        userPosition.setOrderStayFee(allStayFee);
        userPosition.setOrderStayDays(1);


        BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(6, BigDecimal.ROUND_HALF_UP);
        log.info("用户购买手续费（配资后总资金 * 百分比） = {}", buy_fee_amt);
        userPosition.setOrderFee(buy_fee_amt);


        BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(6, BigDecimal.ROUND_HALF_UP);
        log.info("用户购买印花税（配资后总资金 * 百分比） = {}", buy_yhs_amt);
        userPosition.setOrderSpread(buy_yhs_amt);

        SiteSpread siteSpread = iSiteSpreadService.findSpreadRateOne(new BigDecimal(stock_crease), buy_amt, stockDz.getStockCode(), now_price);
        BigDecimal spread_rate_amt = new BigDecimal("0");
        if (siteSpread != null) {
            spread_rate_amt = buy_amt.multiply(siteSpread.getSpreadRate()).setScale(6, BigDecimal.ROUND_HALF_UP);
            log.info("用户购买点差费（配资后总资金 * 百分比{}） = {}", siteSpread.getSpreadRate(), spread_rate_amt);
        } else {
            log.info("用户购买点差费（配资后总资金 * 百分比{}） = {}", "设置异常", spread_rate_amt);
        }

        userPosition.setSpreadRatePrice(spread_rate_amt);


        BigDecimal profit_and_lose = new BigDecimal("0");
        userPosition.setProfitAndLose(profit_and_lose);


        BigDecimal all_profit_and_lose = profit_and_lose.subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt);
        userPosition.setAllProfitAndLose(all_profit_and_lose);


        userPosition.setOrderStayDays(Integer.valueOf(0));
        userPosition.setOrderStayFee(new BigDecimal("0"));

        int insertPositionCount = 0;
        this.userPositionMapper.insert(userPosition);
        insertPositionCount = userPosition.getId();
        if (insertPositionCount > 0) {
            //修改用户可用余额= 当前余额-下单金额-买入手续费-印花税-点差费
            //BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual).subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt);
            //修改用户可用余额= 当前余额-下单总金额
            BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual);
            user.setEnableAmt(reckon_enable);
            int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);
            if (updateUserCount > 0) {
                log.info("【用户交易下单】修改用户金额成功");
            } else {
                log.error("用户交易下单】修改用户金额出错");
                throw new Exception("[User transaction order] Error in modifying the user amount");
            }
            //核算代理收入-入仓手续费
//            iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn());
            log.info("【用户交易下单】保存持仓记录成功");
        } else {
            log.error("用户交易下单】保存持仓记录出错");
            throw new Exception("[User transaction order] Error in saving the position record");
        }

        return ServerResponse.createBySuccess("Bulk transaction order successfully placed");
    }

    /**
     * vip抢筹
     */
    @Transactional(isolation = Isolation.SERIALIZABLE)
    @Override
    public ServerResponse buyVipQc(String stockCode, Integer buyNum, Integer buyType, Integer lever, BigDecimal profitTarget, BigDecimal stopTarget, HttpServletRequest request) throws Exception {

        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        User user = this.iUserService.getCurrentRefreshUser(request);

        if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
            return ServerResponse.createByErrorMsg("下单失败，请先实名认证");
        }
        BigDecimal user_enable_amt = user.getEnableAmt();

        log.info("用户 {} 下单，股票id = {} ，数量 = {} , 方向 = {} , 杠杆 = {}", new Object[]{user
                .getId(), stockCode, buyNum, buyType, lever});
        if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
            return ServerResponse.createByErrorMsg("Order failed and account locked");
        }


        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("下单出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("The order failed, and the system settings are wrong.");
        }
        if (siteSetting.getVipQcMaxAmt().compareTo(user_enable_amt) > 0) {
            return ServerResponse.createByErrorMsg("The order failed, and the available balance is less than " + siteSetting.getVipQcMaxAmt());
        }
        Stock stock = null;
        ServerResponse stock_res = this.iStockService.findStockByCode(stockCode);
        if (!stock_res.isSuccess()) {
            return ServerResponse.createByErrorMsg("The order failed, the stock code is wrong.");
        }
        stock = (Stock) stock_res.getData();

        String am_begin = siteSetting.getTransAmBegin();
        String am_end = siteSetting.getTransAmEnd();
        String pm_begin = siteSetting.getTransPmBegin();
        String pm_end = siteSetting.getTransPmEnd();
        boolean am_flag = BuyAndSellUtils.isTransTime(am_begin, am_end);
        boolean pm_flag = BuyAndSellUtils.isTransTime(pm_begin, pm_end);
        log.info("是否在上午交易时间 = {} 是否在下午交易时间 = {}", Boolean.valueOf(am_flag), Boolean.valueOf(pm_flag));

        if (!am_flag && !pm_flag) {
            return ServerResponse.createByErrorMsg("The order failed and was not within the trading period");
        }
        // 判断是否在后台设置中，如果在，则不允许购买
        if (isHoliday()) {
            return ServerResponse.createByErrorMsg("It cannot be traded on weekends or holidays.");
        }
        if (stock.getIsLock().intValue() != 0) {
            return ServerResponse.createByErrorMsg("The order failed, and the current stock cannot be traded.");
        }

        List dbPosition = findPositionByStockCodeAndTimes(siteSetting.getBuySameTimes().intValue(), stock
                .getStockCode(), user.getId());
        if (dbPosition.size() >= siteSetting.getBuySameNums().intValue()) {
            return ServerResponse.createByErrorMsg("Frequent trading, The same stock position shall not exceed "+siteSetting
                    .getBuySameNums()+" lots within "+siteSetting.getBuySameTimes()+" minutes." );
        }

        Integer transNum = findPositionNumByTimes(siteSetting.getBuyNumTimes().intValue(), user.getId());
        if (transNum.intValue() / 100 >= siteSetting.getBuyNumLots().intValue()) {
            return ServerResponse.createByErrorMsg("Frequent trading, It can't exceed within " + siteSetting
                    .getBuyNumTimes() + " minutes, " + siteSetting.getBuyNumLots() + "hands");
        }

        if (buyNum.intValue() < siteSetting.getBuyMinNum().intValue()) {
            return ServerResponse.createByErrorMsg("The order failed, and the purchase quantity is less than " + siteSetting
                    .getBuyMinNum() + "share");
        }
        if (buyNum.intValue() > siteSetting.getBuyMaxNum().intValue()) {
            return ServerResponse.createByErrorMsg("Failed to place an order, and the number of purchases is greater than " + siteSetting
                    .getBuyMaxNum() + "share");
        }
        BigDecimal now_price;
        StockListVO stockListVO = new StockListVO();
        StockCoin stockCoin = new StockCoin();
        //股票
        stockListVO = SinaStockApi.assembleStockListVO(SinaStockApi.getSinaStock(stock.getStockGid()));
        now_price = new BigDecimal(stockListVO.getNowPrice());
        if (now_price.compareTo(new BigDecimal("0")) == 0) {
            return ServerResponse.createByErrorMsg("Quote 0, please try again later.");
        }


        double stock_crease = stockListVO.getHcrate().doubleValue();


        BigDecimal maxRisePercent = new BigDecimal("0");
        if (stock.getStockPlate() != null) {
            maxRisePercent = new BigDecimal("0.2");
            //maxRisePercent=siteSetting.getKcCreaseMaxPercent().divide(new BigDecimal("100"),2, RoundingMode.DOWN);
            log.info("【科创股票】");
        } else {
            maxRisePercent = new BigDecimal("0.1");
            //maxRisePercent = siteSetting.getCreaseMaxPercent().divide(new BigDecimal("100"),2, RoundingMode.DOWN);
            log.info("【普通A股】");
        }

        if (stockListVO.getName().startsWith("ST") || stockListVO.getName().endsWith("退")) {
            return ServerResponse.createByErrorMsg("ST and delisted stocks cannot be entered.");
        }

        BigDecimal zsPrice = new BigDecimal(stockListVO.getPreclose_px());

        BigDecimal ztPrice = zsPrice.multiply(maxRisePercent).add(zsPrice);
        ztPrice = ztPrice.setScale(6, BigDecimal.ROUND_HALF_UP);
        BigDecimal chaPrice = ztPrice.subtract(zsPrice);

        BigDecimal ztRate = chaPrice.multiply(new BigDecimal("100")).divide(zsPrice, 6, 4);

        log.info("当前涨跌幅 = {} % , 涨停幅度 = {} %", Double.valueOf(stock_crease), ztRate);
//        if ((new BigDecimal(String.valueOf(stock_crease))).compareTo(ztRate) == 0 && buyType
//                .intValue() == 0) {
//            return ServerResponse.createByErrorMsg("当前股票已涨停不能Buy Up");
//        }


        if (stock.getStockPlate() == null || StringUtils.isEmpty(stock.getStockPlate())) {

            int maxcrease = siteSetting.getCreaseMaxPercent().intValue();
            int maxDecrease = siteSetting.getCyDecreaseMaxPercent().intValue();

            if (stock_crease > 0.0D &&
                    stock_crease >= maxcrease) {
                return ServerResponse.createBySuccess("The current transaction cannot be bought.");
                //return ServerResponse.createByErrorMsg("下单失败，股票当前涨幅:" + stock_crease + ",大于最大涨幅:" + maxcrease);
            }


            if (stock_crease < 0.0D &&
                    -stock_crease > maxDecrease) {
                //return ServerResponse.createByErrorMsg("下单失败，股票当前跌幅:" + stock_crease + ",大于最大跌幅:" + maxcrease);
                return ServerResponse.createBySuccess("The current transaction cannot be bought.");
            }

        } else if ("创业".equals(stock.getStockPlate())) {

            int maxcrease = siteSetting.getCyCreaseMaxPercent().intValue();
            int maxDecrease = siteSetting.getCyDecreaseMaxPercent().intValue();

            if (stock_crease > 0.0D &&
                    stock_crease >= maxcrease) {
                return ServerResponse.createBySuccess("The current transaction cannot be bought.");
                //return ServerResponse.createByErrorMsg("下单失败，创业股当前涨幅:" + stock_crease + ",大于最大涨幅:" + maxcrease);
            }


            if (stock_crease < 0.0D &&
                    -stock_crease > maxDecrease) {
                return ServerResponse.createBySuccess("The current transaction cannot be bought.");
                // return ServerResponse.createByErrorMsg("下单失败，创业股当前跌幅:" + stock_crease + ",大于最大跌幅:" + maxcrease);
            }
        } else {

            int maxcrease = siteSetting.getKcCreaseMaxPercent().intValue();
            int maxDecrease = siteSetting.getKcDecreaseMaxPercent().intValue();

            if (stock_crease > 0.0D &&
                    stock_crease >= maxcrease) {
                return ServerResponse.createBySuccess("The current transaction cannot be bought.");
                //   return ServerResponse.createByErrorMsg("下单失败，科创股当前涨幅:" + stock_crease + ",大于最大涨幅:" + maxcrease);
            }


            if (stock_crease < 0.0D &&
                    -stock_crease > maxDecrease) {
                return ServerResponse.createBySuccess("The current transaction cannot be bought.");
                // return ServerResponse.createByErrorMsg("下单失败，科创股当前跌幅:" + stock_crease + ",大于最大跌幅:" + maxcrease);
            }
        }


        ServerResponse serverResponse = this.iStockService.selectRateByDaysAndStockCode(stock
                .getStockCode(), siteSetting.getStockDays().intValue());
        if (!serverResponse.isSuccess()) {
            return serverResponse;
        }
        BigDecimal daysRate = (BigDecimal) serverResponse.getData();
        log.info("股票 {} ， {} 天内 涨幅 {} , 设置的涨幅 = {}", new Object[]{stock.getStockCode(), siteSetting
                .getStockDays(), daysRate, siteSetting.getStockRate()});

        if (daysRate != null && siteSetting.getStockRate().compareTo(daysRate) == -1) {
            return ServerResponse.createByErrorMsg(siteSetting.getStockDays() + "The increase in the day exceeded  " + siteSetting
                    .getStockRate() + "Can't trade ");
        }


        //BigDecimal buy_amt = now_price.multiply(new BigDecimal(buyNum.intValue())).divide(new BigDecimal(lever.intValue())).setScale(4, BigDecimal.ROUND_HALF_UP);
        BigDecimal buy_amt = now_price.multiply(new BigDecimal(buyNum.intValue()));


        //BigDecimal buy_amt_autual = now_price.multiply(new BigDecimal(buyNum.intValue())).divide(new BigDecimal(lever.intValue()), 2, 4);
        BigDecimal buy_amt_autual = buy_amt.divide(new BigDecimal(lever.intValue()), 2, 4);


        int compareInt = buy_amt_autual.compareTo(new BigDecimal(siteSetting.getBuyMinAmt().intValue()));
        if (compareInt == -1) {
            return ServerResponse.createByErrorMsg("The order failed, and the purchase amount is less than " + siteSetting
                    .getBuyMinAmt() + "USD");
        }


        BigDecimal max_buy_amt = user_enable_amt.multiply(siteSetting.getBuyMaxAmtPercent());
        int compareCwInt = buy_amt_autual.compareTo(max_buy_amt);
        if (compareCwInt == 1) {
            return ServerResponse.createByErrorMsg("If the order fails, it cannot exceed the available funds " + siteSetting
                    .getBuyMaxAmtPercent().multiply(new BigDecimal("100")) + "%");
        }


        int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual);
        log.info("用户可用金额 = {}  实际购买金额 =  {}", user_enable_amt, buy_amt_autual);
        log.info("比较 用户金额 和 实际 购买金额 =  {}", Integer.valueOf(compareUserAmtInt));
        if (compareUserAmtInt == -1) {
            return ServerResponse.createByErrorMsg("The order failed, and the available amount was less than " + buy_amt_autual + "USD");
        }

//        if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) {
//            return ServerResponse.createByErrorMsg("失败，指数总资金小于0");
//        }

        UserPosition userPosition = new UserPosition();

        if (profitTarget != null && profitTarget.compareTo(new BigDecimal("0")) > 0) {
            userPosition.setProfitTargetPrice(profitTarget);
        }
        if (stopTarget != null && stopTarget.compareTo(new BigDecimal("0")) > 0) {
            userPosition.setStopTargetPrice(stopTarget);
        }


        userPosition.setPositionType(user.getAccountType());
        userPosition.setPositionSn(KeyUtils.getUniqueKey());
        userPosition.setUserId(user.getId());
        userPosition.setNickName(user.getRealName());
        userPosition.setAgentId(user.getAgentId());
        userPosition.setStockCode(stock.getStockCode());
        userPosition.setStockName(stock.getStockName());
        userPosition.setStockGid(stock.getStockGid());
        userPosition.setStockSpell(stock.getStockSpell());
        userPosition.setBuyOrderId(GeneratePosition.getPositionId());
        userPosition.setBuyOrderTime(new Date());
        userPosition.setBuyOrderPrice(now_price);
        userPosition.setOrderDirection((buyType.intValue() == 0) ? "Buy Up" : "Buy Down");

        userPosition.setOrderNum(buyNum);


        if (stock.getStockPlate() != null) {
            userPosition.setStockPlate(stock.getStockPlate());
        }


        userPosition.setIsLock(Integer.valueOf(0));


        userPosition.setOrderLever(lever);


        userPosition.setOrderTotalPrice(buy_amt);

        //递延费特殊处理
        BigDecimal stayFee = userPosition.getOrderTotalPrice().multiply(siteSetting.getStayFee());
        BigDecimal allStayFee = stayFee.multiply(new BigDecimal(1));
        userPosition.setOrderStayFee(allStayFee);
        userPosition.setOrderStayDays(1);


        BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(6, BigDecimal.ROUND_HALF_UP);
        log.info("用户购买手续费（配资后总资金 * 百分比） = {}", buy_fee_amt);
        userPosition.setOrderFee(buy_fee_amt);


        BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(6, BigDecimal.ROUND_HALF_UP);
        log.info("用户购买印花税（配资后总资金 * 百分比） = {}", buy_yhs_amt);
        userPosition.setOrderSpread(buy_yhs_amt);

        SiteSpread siteSpread = iSiteSpreadService.findSpreadRateOne(new BigDecimal(stock_crease), buy_amt, stock.getStockCode(), now_price);
        BigDecimal spread_rate_amt = new BigDecimal("0");
        if (siteSpread != null) {
            spread_rate_amt = buy_amt.multiply(siteSpread.getSpreadRate()).setScale(6, BigDecimal.ROUND_HALF_UP);
            log.info("用户购买点差费（配资后总资金 * 百分比{}） = {}", siteSpread.getSpreadRate(), spread_rate_amt);
        } else {
            log.info("用户购买点差费（配资后总资金 * 百分比{}） = {}", "设置异常", spread_rate_amt);
        }

        userPosition.setSpreadRatePrice(spread_rate_amt);


        BigDecimal profit_and_lose = new BigDecimal("0");
        userPosition.setProfitAndLose(profit_and_lose);


        BigDecimal all_profit_and_lose = profit_and_lose.subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt);
        userPosition.setAllProfitAndLose(all_profit_and_lose);


        userPosition.setOrderStayDays(Integer.valueOf(0));
        userPosition.setOrderStayFee(new BigDecimal("0"));

        int insertPositionCount = 0;
        this.userPositionMapper.insert(userPosition);
        insertPositionCount = userPosition.getId();
        if (insertPositionCount > 0) {
            //修改用户可用余额= 当前余额-下单金额-买入手续费-印花税-点差费
            //BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual).subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt);
            //修改用户可用余额= 当前余额-下单总金额
            BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual);
            user.setEnableAmt(reckon_enable);
            int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);
            if (updateUserCount > 0) {
                log.info("【用户交易下单】修改用户金额成功");
            } else {
                log.error("用户交易下单】修改用户金额出错");
                throw new Exception("[User transaction order] Error in modifying the user amount");
            }
            //核算代理收入-入仓手续费
//            iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn());
            log.info("【用户交易下单】保存持仓记录成功");
        } else {
            log.error("用户交易下单】保存持仓记录出错");
            throw new Exception("[User transaction order] Error in saving the position record");
        }

        return ServerResponse.createBySuccess("Vip rushed to place an order successfully");
    }

    @Override
    public ServerResponse queryPositionDetails(String phone, Integer userId, String positionNo, String startAmount, int pageNum, int pageSize) {
        Page<StPositionDetailsVo> page = PageHelper.startPage(pageNum, pageSize);

        String beginAmount = "";
        String endAmount = "";
        if (StringUtils.isNotBlank(startAmount)){
            String[] splitAmount = startAmount.split(",");
            List<String> amountList = Arrays.asList(splitAmount);
            if (amountList.size() == 2) {
                beginAmount = amountList.get(0);
                endAmount = amountList.get(1);
            }
        }

        List<StPositionDetailsVo> list = userPositionDetailMapper.queryPositionDetails(phone, userId, positionNo, beginAmount, endAmount);

        PageInfo pageInfo = new PageInfo(page);
        pageInfo.setList(list);
        return ServerResponse.createBySuccess(pageInfo);
    }

    @Override
    @Transactional
    public ServerResponse updateDetails(StPositionDetailsVo vo) {

        // 详情id
        Integer id = vo.getId();
        if (null == id) {
            return ServerResponse.createByErrorMsg("参数错误【id】");
        }

        UserPositionDetail oldDetail = userPositionDetailMapper.selectById(id);
        if (null == oldDetail) {
            return ServerResponse.createByErrorMsg("订单详情不存在【id: "+id+"】");
        }

        Integer lastNum = vo.getLastNum();
        Integer orderNum = vo.getOrderNum();
        BigDecimal initPrice = vo.getInitPrice();
        String orderTime = vo.getOrderTime();

        UserPositionDetail positionDetail = new UserPositionDetail();
        positionDetail.setId(id);
        positionDetail.setLastNum(lastNum);
        positionDetail.setOrderNum(orderNum);
        positionDetail.setInitPrice(initPrice);
        positionDetail.setOrderTime(new Date());


        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if (siteSetting == null) {
            log.error("下单出错，网站设置表不存在");
            return ServerResponse.createByErrorMsg("下单出错，网站设置表不存在.");
        }

        // 如果修改的是买入金额，需要更新总订单表的initPrice
        String type = vo.getType();
        if (UserPositionDetailVo.TYPE_BUY.equals(type)) {
            BigDecimal oldDetailInitPrice = oldDetail.getInitPrice();
            // 查询除了本单外的所有购买详情的金额，重新计算总订单的金额
            Integer positionId = oldDetail.getPositionId();
            Integer oldDetailId = oldDetail.getId();
            List<UserPositionDetail> list = userPositionDetailMapper.queryListByPositionId(positionId, oldDetailId);

            UserPosition position = new UserPosition();
            position.setId(positionId);
            if (null == list || list.isEmpty()) {
                // 说明只有一次购买
                position.setInitPrice(initPrice);

                String market = oldDetail.getStockGid();
                position.setBuyOrderPrice(initPrice);

            }else {
                // 总表的initPrice
                BigDecimal bigDecimal = oldDetailInitPrice;
                for (UserPositionDetail userPositionDetail : list) {
                    BigDecimal price = userPositionDetail.getInitPrice();
                    bigDecimal = bigDecimal.add(price).divide(new BigDecimal("2")).setScale(6, RoundingMode.HALF_UP);
                }

                position.setInitPrice(bigDecimal);

                String market = oldDetail.getStockGid();
                position.setBuyOrderPrice(bigDecimal);
            }
            userPositionMapper.updateById(position);
        }


        // 新增修改的记录
        StringBuilder record = new StringBuilder();
        record.append("股票记录->订单号：" + vo.getPositionNo() + "; ");
        record.append("修改时间：" + DateUtils.now() + ";");
        record.append("最终持有数量由" + oldDetail.getLastNum() + "修改为" + lastNum + "; ");
        record.append("订单数量由" + oldDetail.getOrderNum() + "修改为" + orderNum + "; ");
        record.append("订单价格由" + oldDetail.getOrderPrice() + "修改为" + initPrice + ";");
        record.append("订单时间由" + oldDetail.getOrderTime() + "修改为" + orderTime + ";");

        // 修改记录
        LogEditTransactionRecords transactionRecords = new LogEditTransactionRecords();
        transactionRecords.setRecord(record.toString());
        transactionRecords.setOrderNo(vo.getPositionNo());
        transactionRecords.setCreateTime(new Date());
        logEditTransactionRecordsMapper.insert(transactionRecords);

        return ServerResponse.createBySuccess(userPositionDetailMapper.updateById(positionDetail));
    }

    @Override
    @Transactional
    public ServerResponse editFundDetails(StFundDetailsVo vo) {
        Integer id = vo.getId();
        if (null == id) {
            return ServerResponse.createByErrorMsg("参数错误【id】");
        }

        StFundApplyDetail oldDetail = stFundApplyDetailMapper.selectById(id);
        if (null == oldDetail) {
            return ServerResponse.createByErrorMsg("基金订单详情不存在【id: "+id+"】");
        }

        BigDecimal purchaseAmount = vo.getPurchaseAmount();
        BigDecimal purchaseShare = vo.getPurchaseShare();
        String addTime = vo.getAddTime();

        StFundApplyDetail detailsVo = new StFundApplyDetail();
        detailsVo.setId(id);
        detailsVo.setPurchaseShare(purchaseShare);
        detailsVo.setPurchaseAmount(purchaseAmount);
        detailsVo.setAddTime(new Date());
        stFundApplyDetailMapper.updateById(detailsVo);


        // 新增修改的记录
        StringBuilder record = new StringBuilder();
        record.append("基金记录->订单号：" + vo.getOrderNumber() + "; ");
        record.append("修改时间：" + DateUtils.now() + ";");
        record.append("最终持有份额由" + oldDetail.getPurchaseShare() + "修改为" + purchaseShare + "; ");
        record.append("订单价格由" + oldDetail.getPurchaseAmount() + "修改为" + purchaseAmount + ";");
        record.append("订单创建时间由" + oldDetail.getAddTime() + "修改为" + addTime + ";");

        // 修改记录
        LogEditTransactionRecords transactionRecords = new LogEditTransactionRecords();
        transactionRecords.setRecord(record.toString());
        transactionRecords.setOrderNo(vo.getOrderNumber());
        transactionRecords.setCreateTime(new Date());

        return ServerResponse.createBySuccess(logEditTransactionRecordsMapper.insert(transactionRecords));
    }

    @Override
    public ServerResponse queryFundApplyDetails(String phone, Integer userId, String orderNumber, String startAmount, int pageNum, int pageSize) {
        Page<StFundDetailsVo> page = PageHelper.startPage(pageNum, pageSize);

        String beginAmount = "";
        String endAmount = "";
        if (StringUtils.isNotBlank(startAmount)){
            String[] splitAmount = startAmount.split(",");
            List<String> amountList = Arrays.asList(splitAmount);
            if (amountList.size() == 2) {
                beginAmount = amountList.get(0);
                endAmount = amountList.get(1);
            }
        }

        List<StFundDetailsVo> list = userPositionDetailMapper.queryFundApplyDetails(phone, userId, orderNumber, beginAmount, endAmount);

        PageInfo pageInfo = new PageInfo(page);
        pageInfo.setList(list);
        return ServerResponse.createBySuccess(pageInfo);
    }

}